xref: /petsc/src/dm/impls/plex/plextree.c (revision 57168dbe2b4331ffbf7c9254e2e952baf9ea37a0)
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 
20db781477SPatrick Sanan .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);}
299566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)ref));
309566063dSJacob Faibussowitsch   PetscCall(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 
48db781477SPatrick Sanan .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++) {
729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd));
73dcbd3bf7SToby Isaac     if (parent >= dStart && parent <= dEnd) {
74dcbd3bf7SToby Isaac       break;
75dcbd3bf7SToby Isaac     }
76dcbd3bf7SToby Isaac   }
7763a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %" PetscInt_FMT "-cells",dim);
7828b400f6SJacob 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 
849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm,childA,&size));
859566063dSJacob Faibussowitsch     PetscCall(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;
939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,sA,&sParent,NULL));
94dcbd3bf7SToby Isaac       if (sParent == parent) {
95dcbd3bf7SToby Isaac         break;
96dcbd3bf7SToby Isaac       }
97dcbd3bf7SToby Isaac     }
9808401ef6SPierre Jolivet     PetscCheck(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 */
1019566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB));
1029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm,sA,&sConeSize));
1039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sA,&coneA));
1049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sB,&coneB));
1059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm,sA,&oA));
1069566063dSJacob Faibussowitsch     PetscCall(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 
1189566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm,childA,&coneSize));
119dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
1201dca8a05SBarry Smith           PetscCheck(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     }
13108401ef6SPierre Jolivet     PetscCheck(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 */
1359566063dSJacob Faibussowitsch   PetscCall(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 */
1539566063dSJacob Faibussowitsch     PetscCall(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 */
1641dca8a05SBarry Smith       PetscCheck(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 
196db781477SPatrick Sanan .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);
20428b400f6SJacob Faibussowitsch   PetscCheck(mesh->getchildsymmetry,PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented");
2059566063dSJacob Faibussowitsch   PetscCall(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;
2149566063dSJacob Faibussowitsch   PetscCall(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);
2309566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(K, &dim));
2319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
2329566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, labelName, &identity));
2339566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(Kref, labelName, &identityRef));
2349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(Kref, &pRefStart, &pRefEnd));
2359566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionSection));
2369566063dSJacob Faibussowitsch   PetscCall(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++) {
2399566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1));
240da43764aSToby Isaac   }
241da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
242da43764aSToby Isaac     PetscInt q, qSize;
2439566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(identityRef, p, &q));
2449566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize));
245da43764aSToby Isaac     if (qSize > 1) {
2469566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1));
247da43764aSToby Isaac     }
248da43764aSToby Isaac   }
2499566063dSJacob Faibussowitsch   PetscCall(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 
2559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
256da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
257da43764aSToby Isaac       permvals[offset++] = c;
258da43764aSToby Isaac     }
259da43764aSToby Isaac 
2609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
261da43764aSToby Isaac     for (c = cStart; c < cEnd; c++) {
262da43764aSToby Isaac       permvals[offset++] = c + (pEnd - pStart);
263da43764aSToby Isaac     }
264da43764aSToby Isaac   }
2659566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
2669566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetPermutation(unionSection,perm));
2679566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionSection));
2689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionSection,&numUnionPoints));
2699566063dSJacob Faibussowitsch   PetscCall(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;
2739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K,d,&cStart,NULL));
2749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection,cStart-pStart,&cOff));
275da43764aSToby Isaac     if (d < dim) {
2769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K,d+1,&cStart,NULL));
2779566063dSJacob Faibussowitsch       PetscCall(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   }
2849566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionConeSection));
2859566063dSJacob Faibussowitsch   PetscCall(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 
2909566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
2919566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart,&uOff));
2929566063dSJacob Faibussowitsch     PetscCall(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 
2989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
2999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
3009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
301da43764aSToby Isaac     if (uDof) {
3029566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
303da43764aSToby Isaac       coneSizes[uOff] = dof;
304da43764aSToby Isaac     }
305da43764aSToby Isaac   }
3069566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionConeSection));
3079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionConeSection,&numCones));
3089566063dSJacob Faibussowitsch   PetscCall(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 
3149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
3159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(K, p, &cone));
3169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(K, p, &orientation));
3179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart,&uOff));
3189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionConeSection,uOff,&cOff));
319da43764aSToby Isaac     for (c = 0; c < dof; c++) {
320da43764aSToby Isaac       PetscInt e, eOff;
321da43764aSToby Isaac       e                           = cone[c];
3229566063dSJacob Faibussowitsch       PetscCall(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 
3319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
3329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(Kref, p, &cone));
3339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation));
3349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
3359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
336da43764aSToby Isaac     if (uDof) {
3379566063dSJacob Faibussowitsch       PetscCall(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];
3429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof));
343da43764aSToby Isaac         if (eDof) {
3449566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
345da43764aSToby Isaac         }
346da43764aSToby Isaac         else {
3479566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(identityRef, e, &e));
3489566063dSJacob Faibussowitsch           PetscCall(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 
3629566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(K, &KcoordsSec));
3639566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec));
3649566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec));
3659566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));
366da43764aSToby Isaac 
367da43764aSToby Isaac     numVerts = numDimPoints[0];
3689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numVerts * dim,&unionCoords));
3699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(K,0,&vStart,&vEnd));
370da43764aSToby Isaac 
371da43764aSToby Isaac     offset = 0;
372da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
3739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection,v - pStart,&vOff));
3749566063dSJacob Faibussowitsch       PetscCall(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     }
3809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd));
381da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
3829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof));
3839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff));
3849566063dSJacob Faibussowitsch       PetscCall(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   }
3939566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm,ref));
3949566063dSJacob Faibussowitsch   PetscCall(DMSetType(*ref,DMPLEX));
3959566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ref,dim));
3969566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords));
39710f7e118SToby Isaac   /* set the tree */
3989566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm,&parentSection));
3999566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(parentSection,0,numUnionPoints));
40010f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
40110f7e118SToby Isaac     PetscInt uDof, uOff;
40210f7e118SToby Isaac 
4039566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
4049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
4051baa6e33SBarry Smith     if (uDof) PetscCall(PetscSectionSetDof(parentSection,uOff,1));
40610f7e118SToby Isaac   }
4079566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(parentSection));
4089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection,&parentSize));
4099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(parentSize,&parents,parentSize,&childIDs));
41010f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
41110f7e118SToby Isaac     PetscInt uDof, uOff;
41210f7e118SToby Isaac 
4139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof));
4149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff));
41510f7e118SToby Isaac     if (uDof) {
41610f7e118SToby Isaac       PetscInt pOff, parent, parentU;
4179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(parentSection,uOff,&pOff));
4189566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(identityRef,p,&parent));
4199566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, parent - pStart,&parentU));
42010f7e118SToby Isaac       parents[pOff] = parentU;
42110f7e118SToby Isaac       childIDs[pOff] = uOff;
42210f7e118SToby Isaac     }
42310f7e118SToby Isaac   }
4249566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_SetTree(*ref,parentSection,parents,childIDs));
4259566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
4269566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parents,childIDs));
42710f7e118SToby Isaac 
428da43764aSToby Isaac   /* clean up */
4299566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionSection));
4309566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionConeSection));
4319566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&perm));
4329566063dSJacob Faibussowitsch   PetscCall(PetscFree(unionCoords));
4339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(unionCones,unionOrientations));
4349566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coneSizes,numDimPoints));
4350e2cc29aSToby Isaac   PetscFunctionReturn(0);
4360e2cc29aSToby Isaac }
4370e2cc29aSToby Isaac 
4380e2cc29aSToby Isaac /*@
4390e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4400e2cc29aSToby Isaac 
441d083f849SBarry Smith   Collective
4420e2cc29aSToby Isaac 
4430e2cc29aSToby Isaac   Input Parameters:
4440e2cc29aSToby Isaac + comm    - the MPI communicator
4450e2cc29aSToby Isaac . dim     - the spatial dimension
4460e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4470e2cc29aSToby Isaac 
4480e2cc29aSToby Isaac   Output Parameters:
4490e2cc29aSToby Isaac . ref     - the reference tree DMPlex object
4500e2cc29aSToby Isaac 
4510e2cc29aSToby Isaac   Level: intermediate
4520e2cc29aSToby Isaac 
453db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`
4540e2cc29aSToby Isaac @*/
4550e2cc29aSToby Isaac PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
4560e2cc29aSToby Isaac {
4570e2cc29aSToby Isaac   DM_Plex       *mesh;
4580e2cc29aSToby Isaac   DM             K, Kref;
4590e2cc29aSToby Isaac   PetscInt       p, pStart, pEnd;
4600e2cc29aSToby Isaac   DMLabel        identity;
4610e2cc29aSToby Isaac 
4620e2cc29aSToby Isaac   PetscFunctionBegin;
4630e2cc29aSToby Isaac #if 1
4640e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4650e2cc29aSToby Isaac #endif
4660e2cc29aSToby Isaac   /* create a reference element */
4679566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
4689566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(K, "identity"));
4699566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, "identity", &identity));
4709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
4710e2cc29aSToby Isaac   for (p = pStart; p < pEnd; p++) {
4729566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(identity, p, p));
4730e2cc29aSToby Isaac   }
4740e2cc29aSToby Isaac   /* refine it */
4759566063dSJacob Faibussowitsch   PetscCall(DMRefine(K,comm,&Kref));
4760e2cc29aSToby Isaac 
4770e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4780e2cc29aSToby Isaac    * points that appear in both */
4799566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
4800e2cc29aSToby Isaac   mesh = (DM_Plex *) (*ref)->data;
4810e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
4829566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
4839566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&Kref));
484da43764aSToby Isaac   PetscFunctionReturn(0);
485da43764aSToby Isaac }
486da43764aSToby Isaac 
487878b19aaSToby Isaac static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
488878b19aaSToby Isaac {
489878b19aaSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
490878b19aaSToby Isaac   PetscSection   childSec, pSec;
491878b19aaSToby Isaac   PetscInt       p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
492878b19aaSToby Isaac   PetscInt       *offsets, *children, pStart, pEnd;
493878b19aaSToby Isaac 
494878b19aaSToby Isaac   PetscFunctionBegin;
495878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4969566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
4979566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
498878b19aaSToby Isaac   pSec = mesh->parentSection;
499878b19aaSToby Isaac   if (!pSec) PetscFunctionReturn(0);
5009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(pSec,&pSize));
501878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
502878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
503878b19aaSToby Isaac 
504878b19aaSToby Isaac     parMax = PetscMax(parMax,par+1);
505878b19aaSToby Isaac     parMin = PetscMin(parMin,par);
506878b19aaSToby Isaac   }
507878b19aaSToby Isaac   if (parMin > parMax) {
508878b19aaSToby Isaac     parMin = -1;
509878b19aaSToby Isaac     parMax = -1;
510878b19aaSToby Isaac   }
5119566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec));
5129566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(childSec,parMin,parMax));
513878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
514878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
515878b19aaSToby Isaac 
5169566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(childSec,par,1));
517878b19aaSToby Isaac   }
5189566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(childSec));
5199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(childSec,&cSize));
5209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cSize,&children));
5219566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(parMax-parMin,&offsets));
5229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(pSec,&pStart,&pEnd));
523878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
524878b19aaSToby Isaac     PetscInt dof, off, i;
525878b19aaSToby Isaac 
5269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec,p,&dof));
5279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(pSec,p,&off));
528878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
529878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
530878b19aaSToby Isaac 
5319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec,par,&cOff));
532878b19aaSToby Isaac       children[cOff + offsets[par-parMin]++] = p;
533878b19aaSToby Isaac     }
534878b19aaSToby Isaac   }
535878b19aaSToby Isaac   mesh->childSection = childSec;
536878b19aaSToby Isaac   mesh->children = children;
5379566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
538878b19aaSToby Isaac   PetscFunctionReturn(0);
539878b19aaSToby Isaac }
540878b19aaSToby Isaac 
5416dd5a8c8SToby Isaac static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
5426dd5a8c8SToby Isaac {
5436dd5a8c8SToby Isaac   PetscInt       pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5446dd5a8c8SToby Isaac   const PetscInt *vals;
5456dd5a8c8SToby Isaac   PetscSection   secNew;
5466dd5a8c8SToby Isaac   PetscBool      anyNew, globalAnyNew;
5476dd5a8c8SToby Isaac   PetscBool      compress;
5486dd5a8c8SToby Isaac 
5496dd5a8c8SToby Isaac   PetscFunctionBegin;
5509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section,&pStart,&pEnd));
5519566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is,&size));
5529566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is,&vals));
5539566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew));
5549566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(secNew,pStart,pEnd));
5556dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5566dd5a8c8SToby Isaac     PetscInt dof;
5576dd5a8c8SToby Isaac 
5586dd5a8c8SToby Isaac     p = vals[i];
5596dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
5616dd5a8c8SToby Isaac     if (dof) break;
5626dd5a8c8SToby Isaac   }
5636dd5a8c8SToby Isaac   if (i == size) {
5649566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5656dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5666dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5676dd5a8c8SToby Isaac     sizeNew  = 0;
5686dd5a8c8SToby Isaac   }
5696dd5a8c8SToby Isaac   else {
5706dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5716dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5726dd5a8c8SToby Isaac       PetscInt dof, off;
5736dd5a8c8SToby Isaac 
5749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5766dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5776dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5786dd5a8c8SToby Isaac 
5796dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5809566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, q, &qDof));
5816dd5a8c8SToby Isaac         }
5821baa6e33SBarry Smith         if (qDof) PetscCall(PetscSectionAddDof(secNew, p, qDof));
5836dd5a8c8SToby Isaac         else {
5849566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(secNew, p, 1));
5856dd5a8c8SToby Isaac         }
5866dd5a8c8SToby Isaac       }
5876dd5a8c8SToby Isaac     }
5889566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(secNew,&sizeNew));
5909566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sizeNew,&valsNew));
5916dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5926dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5936dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5946dd5a8c8SToby Isaac 
5959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(secNew, p, &dofNew));
5989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(secNew, p, &offNew));
5996dd5a8c8SToby Isaac       count = 0;
6006dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
6016dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
6026dd5a8c8SToby Isaac 
6036dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
6049566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, q, &qDof));
6059566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, q, &qOff));
6066dd5a8c8SToby Isaac         }
6076dd5a8c8SToby Isaac         if (qDof) {
6086dd5a8c8SToby Isaac           PetscInt oldCount = count;
6096dd5a8c8SToby Isaac 
6106dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
6116dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
6126dd5a8c8SToby Isaac 
6136dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
6146dd5a8c8SToby Isaac               if (valsNew[offNew + k] == r) {
6156dd5a8c8SToby Isaac                 break;
6166dd5a8c8SToby Isaac               }
6176dd5a8c8SToby Isaac             }
6186dd5a8c8SToby Isaac             if (k == oldCount) {
6196dd5a8c8SToby Isaac               valsNew[offNew + count++] = r;
6206dd5a8c8SToby Isaac             }
6216dd5a8c8SToby Isaac           }
6226dd5a8c8SToby Isaac         }
6236dd5a8c8SToby Isaac         else {
6246dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
6256dd5a8c8SToby Isaac 
6266dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
6276dd5a8c8SToby Isaac             if (valsNew[offNew + k] == q) {
6286dd5a8c8SToby Isaac               break;
6296dd5a8c8SToby Isaac             }
6306dd5a8c8SToby Isaac           }
6316dd5a8c8SToby Isaac           if (k == oldCount) {
6326dd5a8c8SToby Isaac             valsNew[offNew + count++] = q;
6336dd5a8c8SToby Isaac           }
6346dd5a8c8SToby Isaac         }
6356dd5a8c8SToby Isaac       }
6366dd5a8c8SToby Isaac       if (count < dofNew) {
6379566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secNew, p, count));
6386dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6396dd5a8c8SToby Isaac       }
6406dd5a8c8SToby Isaac     }
6416dd5a8c8SToby Isaac   }
6429566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is,&vals));
6431c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew)));
6446dd5a8c8SToby Isaac   if (!globalAnyNew) {
6459566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secNew));
6466dd5a8c8SToby Isaac     *sectionNew = NULL;
6476dd5a8c8SToby Isaac     *isNew = NULL;
6486dd5a8c8SToby Isaac   }
6496dd5a8c8SToby Isaac   else {
6506dd5a8c8SToby Isaac     PetscBool globalCompress;
6516dd5a8c8SToby Isaac 
6521c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew)));
6536dd5a8c8SToby Isaac     if (compress) {
6546dd5a8c8SToby Isaac       PetscSection secComp;
6556dd5a8c8SToby Isaac       PetscInt *valsComp = NULL;
6566dd5a8c8SToby Isaac 
6579566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp));
6589566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(secComp,pStart,pEnd));
6596dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6606dd5a8c8SToby Isaac         PetscInt dof;
6616dd5a8c8SToby Isaac 
6629566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6639566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secComp, p, dof));
6646dd5a8c8SToby Isaac       }
6659566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(secComp));
6669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(secComp,&sizeNew));
6679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(sizeNew,&valsComp));
6686dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6696dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6706dd5a8c8SToby Isaac 
6719566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secNew, p, &off));
6739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secComp, p, &offNew));
6746dd5a8c8SToby Isaac         for (j = 0; j < dof; j++) {
6756dd5a8c8SToby Isaac           valsComp[offNew + j] = valsNew[off + j];
6766dd5a8c8SToby Isaac         }
6776dd5a8c8SToby Isaac       }
6789566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&secNew));
6796dd5a8c8SToby Isaac       secNew  = secComp;
6809566063dSJacob Faibussowitsch       PetscCall(PetscFree(valsNew));
6816dd5a8c8SToby Isaac       valsNew = valsComp;
6826dd5a8c8SToby Isaac     }
6839566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew));
6846dd5a8c8SToby Isaac   }
6856dd5a8c8SToby Isaac   PetscFunctionReturn(0);
6866dd5a8c8SToby Isaac }
6876dd5a8c8SToby Isaac 
688f7c74593SToby Isaac static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
68966af876cSToby Isaac {
69066af876cSToby Isaac   PetscInt       p, pStart, pEnd, *anchors, size;
69166af876cSToby Isaac   PetscInt       aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
69266af876cSToby Isaac   PetscSection   aSec;
693f9f063d4SToby Isaac   DMLabel        canonLabel;
69466af876cSToby Isaac   IS             aIS;
69566af876cSToby Isaac 
69666af876cSToby Isaac   PetscFunctionBegin;
69766af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm,&pStart,&pEnd));
6999566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm,"canonical",&canonLabel));
70066af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
70166af876cSToby Isaac     PetscInt parent;
70266af876cSToby Isaac 
703f9f063d4SToby Isaac     if (canonLabel) {
704f9f063d4SToby Isaac       PetscInt canon;
705f9f063d4SToby Isaac 
7069566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel,p,&canon));
707f9f063d4SToby Isaac       if (p != canon) continue;
708f9f063d4SToby Isaac     }
7099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm,p,&parent,NULL));
71066af876cSToby Isaac     if (parent != p) {
71166af876cSToby Isaac       aMin = PetscMin(aMin,p);
71266af876cSToby Isaac       aMax = PetscMax(aMax,p+1);
71366af876cSToby Isaac     }
71466af876cSToby Isaac   }
71566af876cSToby Isaac   if (aMin > aMax) {
71666af876cSToby Isaac     aMin = -1;
71766af876cSToby Isaac     aMax = -1;
71866af876cSToby Isaac   }
7199566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&aSec));
7209566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(aSec,aMin,aMax));
72166af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
72266af876cSToby Isaac     PetscInt parent, ancestor = p;
72366af876cSToby Isaac 
724f9f063d4SToby Isaac     if (canonLabel) {
725f9f063d4SToby Isaac       PetscInt canon;
726f9f063d4SToby Isaac 
7279566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel,p,&canon));
728f9f063d4SToby Isaac       if (p != canon) continue;
729f9f063d4SToby Isaac     }
7309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm,p,&parent,NULL));
73166af876cSToby Isaac     while (parent != ancestor) {
73266af876cSToby Isaac       ancestor = parent;
7339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,ancestor,&parent,NULL));
73466af876cSToby Isaac     }
73566af876cSToby Isaac     if (ancestor != p) {
73666af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
73766af876cSToby Isaac 
7389566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
7399566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(aSec,p,closureSize));
7409566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
74166af876cSToby Isaac     }
74266af876cSToby Isaac   }
7439566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(aSec));
7449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(aSec,&size));
7459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size,&anchors));
74666af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
74766af876cSToby Isaac     PetscInt parent, ancestor = p;
74866af876cSToby Isaac 
749f9f063d4SToby Isaac     if (canonLabel) {
750f9f063d4SToby Isaac       PetscInt canon;
751f9f063d4SToby Isaac 
7529566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel,p,&canon));
753f9f063d4SToby Isaac       if (p != canon) continue;
754f9f063d4SToby Isaac     }
7559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm,p,&parent,NULL));
75666af876cSToby Isaac     while (parent != ancestor) {
75766af876cSToby Isaac       ancestor = parent;
7589566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,ancestor,&parent,NULL));
75966af876cSToby Isaac     }
76066af876cSToby Isaac     if (ancestor != p) {
76166af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
76266af876cSToby Isaac 
7639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec,p,&aOff));
76466af876cSToby Isaac 
7659566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
76666af876cSToby Isaac       for (j = 0; j < closureSize; j++) {
76766af876cSToby Isaac         anchors[aOff + j] = closure[2*j];
76866af876cSToby Isaac       }
7699566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure));
77066af876cSToby Isaac     }
77166af876cSToby Isaac   }
7729566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS));
7736dd5a8c8SToby Isaac   {
7746dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7756dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7766dd5a8c8SToby Isaac 
7779566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aSec));
7789566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aIS));
7796dd5a8c8SToby Isaac     while (aSecNew) {
7809566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&aSec));
7819566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&aIS));
7826dd5a8c8SToby Isaac       aSec    = aSecNew;
7836dd5a8c8SToby Isaac       aIS     = aISNew;
7846dd5a8c8SToby Isaac       aSecNew = NULL;
7856dd5a8c8SToby Isaac       aISNew  = NULL;
7869566063dSJacob Faibussowitsch       PetscCall(AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew));
7876dd5a8c8SToby Isaac     }
7886dd5a8c8SToby Isaac   }
7899566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm,aSec,aIS));
7909566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&aSec));
7919566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&aIS));
79266af876cSToby Isaac   PetscFunctionReturn(0);
79366af876cSToby Isaac }
79466af876cSToby Isaac 
7956461c1adSToby Isaac static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp)
7966461c1adSToby Isaac {
7976461c1adSToby Isaac   PetscFunctionBegin;
7986461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
7996461c1adSToby Isaac     PetscInt i, alldof;
8006461c1adSToby Isaac     const PetscInt *supp;
8016461c1adSToby Isaac     PetscInt count = 0;
8026461c1adSToby Isaac 
8039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm,p,&alldof));
8049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm,p,&supp));
8056461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
8066461c1adSToby Isaac       PetscInt q = supp[i], numCones, j;
8076461c1adSToby Isaac       const PetscInt *cone;
8086461c1adSToby Isaac 
8099566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm,q,&numCones));
8109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm,q,&cone));
8116461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
8126461c1adSToby Isaac         if (cone[j] == p) break;
8136461c1adSToby Isaac       }
8146461c1adSToby Isaac       if (j < numCones) count++;
8156461c1adSToby Isaac     }
8166461c1adSToby Isaac     numTrueSupp[p] = count;
8176461c1adSToby Isaac   }
8186461c1adSToby Isaac   *dof = numTrueSupp[p];
8196461c1adSToby Isaac   PetscFunctionReturn(0);
8206461c1adSToby Isaac }
8216461c1adSToby Isaac 
822776742edSToby Isaac static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
823776742edSToby Isaac {
824776742edSToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
825776742edSToby Isaac   PetscSection   newSupportSection;
826776742edSToby Isaac   PetscInt       newSize, *newSupports, pStart, pEnd, p, d, depth;
8276461c1adSToby Isaac   PetscInt       *numTrueSupp;
828776742edSToby Isaac   PetscInt       *offsets;
829776742edSToby Isaac 
830776742edSToby Isaac   PetscFunctionBegin;
831776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
832776742edSToby Isaac   /* symmetrize the hierarchy */
8339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm,&depth));
8349566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection));
8359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm,&pStart,&pEnd));
8369566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSupportSection,pStart,pEnd));
8379566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd,&offsets));
8389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd,&numTrueSupp));
8396461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8406461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
841776742edSToby Isaac    * parent(q) */
842776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8439566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm,d,&pStart,&pEnd));
844776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
845776742edSToby Isaac       PetscInt dof, q, qdof, parent;
846776742edSToby Isaac 
8479566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp));
8489566063dSJacob Faibussowitsch       PetscCall(PetscSectionAddDof(newSupportSection, p, dof));
849776742edSToby Isaac       q    = p;
8509566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,q,&parent,NULL));
851776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
852776742edSToby Isaac         q = parent;
853776742edSToby Isaac 
8549566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp));
8559566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection,p,qdof));
8569566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection,q,dof));
8579566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm,q,&parent,NULL));
858776742edSToby Isaac       }
859776742edSToby Isaac     }
860776742edSToby Isaac   }
8619566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSupportSection));
8629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSupportSection,&newSize));
8639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(newSize,&newSupports));
864776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm,d,&pStart,&pEnd));
866776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
867776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
868776742edSToby Isaac 
8699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
8719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof));
8729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff));
873776742edSToby Isaac       for (i = 0; i < dof; i++) {
8746461c1adSToby Isaac         PetscInt numCones, j;
8756461c1adSToby Isaac         const PetscInt *cone;
8766461c1adSToby Isaac         PetscInt q = mesh->supports[off + i];
8776461c1adSToby Isaac 
8789566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm,q,&numCones));
8799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm,q,&cone));
8806461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8816461c1adSToby Isaac           if (cone[j] == p) break;
8826461c1adSToby Isaac         }
8836461c1adSToby Isaac         if (j < numCones) newSupports[newOff+offsets[p]++] = q;
884776742edSToby Isaac       }
885776742edSToby Isaac 
886776742edSToby Isaac       q    = p;
8879566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,q,&parent,NULL));
888776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
889776742edSToby Isaac         q = parent;
8909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof));
8919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
8929566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff));
893776742edSToby Isaac         for (i = 0; i < qdof; i++) {
8946461c1adSToby Isaac           PetscInt numCones, j;
8956461c1adSToby Isaac           const PetscInt *cone;
8966461c1adSToby Isaac           PetscInt r = mesh->supports[qoff + i];
8976461c1adSToby Isaac 
8989566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm,r,&numCones));
8999566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm,r,&cone));
9006461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9016461c1adSToby Isaac             if (cone[j] == q) break;
9026461c1adSToby Isaac           }
9036461c1adSToby Isaac           if (j < numCones) newSupports[newOff+offsets[p]++] = r;
904776742edSToby Isaac         }
905776742edSToby Isaac         for (i = 0; i < dof; i++) {
9066461c1adSToby Isaac           PetscInt numCones, j;
9076461c1adSToby Isaac           const PetscInt *cone;
9086461c1adSToby Isaac           PetscInt r = mesh->supports[off + i];
9096461c1adSToby Isaac 
9109566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm,r,&numCones));
9119566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm,r,&cone));
9126461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
9136461c1adSToby Isaac             if (cone[j] == p) break;
9146461c1adSToby Isaac           }
9156461c1adSToby Isaac           if (j < numCones) newSupports[newqOff+offsets[q]++] = r;
916776742edSToby Isaac         }
9179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm,q,&parent,NULL));
918776742edSToby Isaac       }
919776742edSToby Isaac     }
920776742edSToby Isaac   }
9219566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
922776742edSToby Isaac   mesh->supportSection = newSupportSection;
9239566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
924776742edSToby Isaac   mesh->supports = newSupports;
9259566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
9269566063dSJacob Faibussowitsch   PetscCall(PetscFree(numTrueSupp));
927776742edSToby Isaac 
928776742edSToby Isaac   PetscFunctionReturn(0);
929776742edSToby Isaac }
930776742edSToby Isaac 
931f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat);
932f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat);
933f7c74593SToby Isaac 
934776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
935f9f063d4SToby Isaac {
936f9f063d4SToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
937f9f063d4SToby Isaac   DM             refTree;
938f9f063d4SToby Isaac   PetscInt       size;
939f9f063d4SToby Isaac 
940f9f063d4SToby Isaac   PetscFunctionBegin;
941f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
942f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
9439566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)parentSection));
9449566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
945f9f063d4SToby Isaac   mesh->parentSection = parentSection;
9469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection,&size));
947f9f063d4SToby Isaac   if (parents != mesh->parents) {
9489566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->parents));
9499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size,&mesh->parents));
9509566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->parents, parents, size));
951f9f063d4SToby Isaac   }
952f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
9539566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->childIDs));
9549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size,&mesh->childIDs));
9559566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size));
956f9f063d4SToby Isaac   }
9579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm,&refTree));
958f9f063d4SToby Isaac   if (refTree) {
959f9f063d4SToby Isaac     DMLabel canonLabel;
960f9f063d4SToby Isaac 
9619566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(refTree,"canonical",&canonLabel));
962f9f063d4SToby Isaac     if (canonLabel) {
963f9f063d4SToby Isaac       PetscInt i;
964f9f063d4SToby Isaac 
965f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
966f9f063d4SToby Isaac         PetscInt canon;
9679566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
968f9f063d4SToby Isaac         if (canon >= 0) {
969f9f063d4SToby Isaac           mesh->childIDs[i] = canon;
970f9f063d4SToby Isaac         }
971f9f063d4SToby Isaac       }
972f9f063d4SToby Isaac     }
973f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
9746e0288c8SStefano Zampini   } else {
975f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
976f9f063d4SToby Isaac   }
9779566063dSJacob Faibussowitsch   PetscCall(DMPlexTreeSymmetrize(dm));
978f9f063d4SToby Isaac   if (computeCanonical) {
979f9f063d4SToby Isaac     PetscInt d, dim;
980f9f063d4SToby Isaac 
981f9f063d4SToby Isaac     /* add the canonical label */
9829566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm,&dim));
9839566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm,"canonical"));
984f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
985f9f063d4SToby Isaac       PetscInt p, dStart, dEnd, canon = -1, cNumChildren;
986f9f063d4SToby Isaac       const PetscInt *cChildren;
987f9f063d4SToby Isaac 
9889566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm,d,&dStart,&dEnd));
989f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
9909566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren));
991f9f063d4SToby Isaac         if (cNumChildren) {
992f9f063d4SToby Isaac           canon = p;
993f9f063d4SToby Isaac           break;
994f9f063d4SToby Isaac         }
995f9f063d4SToby Isaac       }
996f9f063d4SToby Isaac       if (canon == -1) continue;
997f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
998f9f063d4SToby Isaac         PetscInt numChildren, i;
999f9f063d4SToby Isaac         const PetscInt *children;
1000f9f063d4SToby Isaac 
10019566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm,p,&numChildren,&children));
1002f9f063d4SToby Isaac         if (numChildren) {
100363a3b9bcSJacob Faibussowitsch           PetscCheck(numChildren == cNumChildren,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"All parent points in a stratum should have the same number of children: %" PetscInt_FMT " != %" PetscInt_FMT, numChildren, cNumChildren);
10049566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm,"canonical",p,canon));
1005f9f063d4SToby Isaac           for (i = 0; i < numChildren; i++) {
10069566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm,"canonical",children[i],cChildren[i]));
1007f9f063d4SToby Isaac           }
1008f9f063d4SToby Isaac         }
1009f9f063d4SToby Isaac       }
1010f9f063d4SToby Isaac     }
1011f9f063d4SToby Isaac   }
10121baa6e33SBarry Smith   if (exchangeSupports) PetscCall(DMPlexTreeExchangeSupports(dm));
1013f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
1014f7c74593SToby Isaac   /* reset anchors */
10159566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm,NULL,NULL));
1016f9f063d4SToby Isaac   PetscFunctionReturn(0);
1017f9f063d4SToby Isaac }
1018f9f063d4SToby Isaac 
10190b7167a0SToby Isaac /*@
10200b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
10210b7167a0SToby Isaac   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
10220b7167a0SToby Isaac   tree root.
10230b7167a0SToby Isaac 
10240b7167a0SToby Isaac   Collective on dm
10250b7167a0SToby Isaac 
10260b7167a0SToby Isaac   Input Parameters:
10270b7167a0SToby Isaac + dm - the DMPlex object
10280b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
10290b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
10300b7167a0SToby Isaac . parents - a list of the point parents; copied, can be destroyed
10310b7167a0SToby Isaac - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
10320b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
10330b7167a0SToby Isaac 
10340b7167a0SToby Isaac   Level: intermediate
10350b7167a0SToby Isaac 
1036db781477SPatrick Sanan .seealso: `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
10370b7167a0SToby Isaac @*/
1038b2f41788SToby Isaac PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
10390b7167a0SToby Isaac {
10400b7167a0SToby Isaac   PetscFunctionBegin;
10419566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE));
10420b7167a0SToby Isaac   PetscFunctionReturn(0);
10430b7167a0SToby Isaac }
10440b7167a0SToby Isaac 
1045b2f41788SToby Isaac /*@
1046b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1047b2f41788SToby Isaac   Collective on dm
1048b2f41788SToby Isaac 
1049f899ff85SJose E. Roman   Input Parameter:
1050b2f41788SToby Isaac . dm - the DMPlex object
1051b2f41788SToby Isaac 
1052b2f41788SToby Isaac   Output Parameters:
1053b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1054b2f41788SToby Isaac                   offset indexes the parent and childID list
1055b2f41788SToby Isaac . parents - a list of the point parents
1056b2f41788SToby Isaac . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1057b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1058b2f41788SToby Isaac . childSection - the inverse of the parent section
1059b2f41788SToby Isaac - children - a list of the point children
1060b2f41788SToby Isaac 
1061b2f41788SToby Isaac   Level: intermediate
1062b2f41788SToby Isaac 
1063db781477SPatrick Sanan .seealso: `DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
1064b2f41788SToby Isaac @*/
1065b2f41788SToby Isaac PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1066b2f41788SToby Isaac {
1067b2f41788SToby Isaac   DM_Plex        *mesh = (DM_Plex *)dm->data;
1068b2f41788SToby Isaac 
1069b2f41788SToby Isaac   PetscFunctionBegin;
1070b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1071b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1072b2f41788SToby Isaac   if (parents)       *parents       = mesh->parents;
1073b2f41788SToby Isaac   if (childIDs)      *childIDs      = mesh->childIDs;
1074b2f41788SToby Isaac   if (childSection)  *childSection  = mesh->childSection;
1075b2f41788SToby Isaac   if (children)      *children      = mesh->children;
1076b2f41788SToby Isaac   PetscFunctionReturn(0);
1077b2f41788SToby Isaac }
1078b2f41788SToby Isaac 
1079d961a43aSToby Isaac /*@
1080eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1081d961a43aSToby Isaac 
1082d961a43aSToby Isaac   Input Parameters:
1083d961a43aSToby Isaac + dm - the DMPlex object
1084d961a43aSToby Isaac - point - the query point
1085d961a43aSToby Isaac 
1086d961a43aSToby Isaac   Output Parameters:
1087d961a43aSToby Isaac + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent
1088d961a43aSToby Isaac - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point
1089d961a43aSToby Isaac             does not have a parent
1090d961a43aSToby Isaac 
1091d961a43aSToby Isaac   Level: intermediate
1092d961a43aSToby Isaac 
1093db781477SPatrick Sanan .seealso: `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()`
1094d961a43aSToby Isaac @*/
1095d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1096d961a43aSToby Isaac {
1097d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1098d961a43aSToby Isaac   PetscSection   pSec;
1099d961a43aSToby Isaac 
1100d961a43aSToby Isaac   PetscFunctionBegin;
1101d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1102d961a43aSToby Isaac   pSec = mesh->parentSection;
1103d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1104d961a43aSToby Isaac     PetscInt dof;
1105d961a43aSToby Isaac 
11069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof (pSec, point, &dof));
1107d961a43aSToby Isaac     if (dof) {
1108d961a43aSToby Isaac       PetscInt off;
1109d961a43aSToby Isaac 
11109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset (pSec, point, &off));
1111d961a43aSToby Isaac       if (parent)  *parent = mesh->parents[off];
1112d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
1113d961a43aSToby Isaac       PetscFunctionReturn(0);
1114d961a43aSToby Isaac     }
1115d961a43aSToby Isaac   }
1116d961a43aSToby Isaac   if (parent) {
1117d961a43aSToby Isaac     *parent = point;
1118d961a43aSToby Isaac   }
1119d961a43aSToby Isaac   if (childID) {
1120d961a43aSToby Isaac     *childID = 0;
1121d961a43aSToby Isaac   }
1122d961a43aSToby Isaac   PetscFunctionReturn(0);
1123d961a43aSToby Isaac }
1124d961a43aSToby Isaac 
1125d961a43aSToby Isaac /*@C
1126eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1127d961a43aSToby Isaac 
1128d961a43aSToby Isaac   Input Parameters:
1129d961a43aSToby Isaac + dm - the DMPlex object
1130d961a43aSToby Isaac - point - the query point
1131d961a43aSToby Isaac 
1132d961a43aSToby Isaac   Output Parameters:
1133d961a43aSToby Isaac + numChildren - if not NULL, set to the number of children
1134d961a43aSToby Isaac - children - if not NULL, set to a list children, or set to NULL if the point has no children
1135d961a43aSToby Isaac 
1136d961a43aSToby Isaac   Level: intermediate
1137d961a43aSToby Isaac 
1138d961a43aSToby Isaac   Fortran Notes:
1139d961a43aSToby Isaac   Since it returns an array, this routine is only available in Fortran 90, and you must
1140d961a43aSToby Isaac   include petsc.h90 in your code.
1141d961a43aSToby Isaac 
1142db781477SPatrick Sanan .seealso: `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()`
1143d961a43aSToby Isaac @*/
1144d961a43aSToby Isaac PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1145d961a43aSToby Isaac {
1146d961a43aSToby Isaac   DM_Plex       *mesh = (DM_Plex *)dm->data;
1147d961a43aSToby Isaac   PetscSection   childSec;
1148d961a43aSToby Isaac   PetscInt       dof = 0;
1149d961a43aSToby Isaac 
1150d961a43aSToby Isaac   PetscFunctionBegin;
1151d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1152d961a43aSToby Isaac   childSec = mesh->childSection;
1153d961a43aSToby Isaac   if (childSec && point >= childSec->pStart && point < childSec->pEnd) {
11549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof (childSec, point, &dof));
1155d961a43aSToby Isaac   }
1156d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1157d961a43aSToby Isaac   if (children) {
1158d961a43aSToby Isaac     if (dof) {
1159d961a43aSToby Isaac       PetscInt off;
1160d961a43aSToby Isaac 
11619566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset (childSec, point, &off));
1162d961a43aSToby Isaac       *children = &mesh->children[off];
1163d961a43aSToby Isaac     }
1164d961a43aSToby Isaac     else {
1165d961a43aSToby Isaac       *children = NULL;
1166d961a43aSToby Isaac     }
1167d961a43aSToby Isaac   }
1168d961a43aSToby Isaac   PetscFunctionReturn(0);
1169d961a43aSToby Isaac }
11700c37af3bSToby Isaac 
117152a3aeb4SToby 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)
1172b3a4bf2aSToby Isaac {
117352a3aeb4SToby Isaac   PetscInt       f, b, p, c, offset, qPoints;
1174b3a4bf2aSToby Isaac 
1175b3a4bf2aSToby Isaac   PetscFunctionBegin;
11769566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(space,nPoints,points,work,NULL,NULL));
117752a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
117852a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
117952a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1180b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1181b3a4bf2aSToby Isaac 
118252a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
118352a3aeb4SToby Isaac         for (c = 0; c < nComps; c++) {
118452a3aeb4SToby Isaac           val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
1185b3a4bf2aSToby Isaac         }
118652a3aeb4SToby Isaac       }
11879566063dSJacob Faibussowitsch       PetscCall(MatSetValue(basisAtPoints,b,f,val,INSERT_VALUES));
1188b3a4bf2aSToby Isaac     }
1189b3a4bf2aSToby Isaac     offset += qPoints;
1190b3a4bf2aSToby Isaac   }
11919566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(basisAtPoints,MAT_FINAL_ASSEMBLY));
11929566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(basisAtPoints,MAT_FINAL_ASSEMBLY));
1193b3a4bf2aSToby Isaac   PetscFunctionReturn(0);
1194b3a4bf2aSToby Isaac }
1195b3a4bf2aSToby Isaac 
1196f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
11970c37af3bSToby Isaac {
11980c37af3bSToby Isaac   PetscDS        ds;
11990c37af3bSToby Isaac   PetscInt       spdim;
12000c37af3bSToby Isaac   PetscInt       numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
12010c37af3bSToby Isaac   const PetscInt *anchors;
1202f7c74593SToby Isaac   PetscSection   aSec;
12030c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
12040c37af3bSToby Isaac   IS             aIS;
12050c37af3bSToby Isaac 
12060c37af3bSToby Isaac   PetscFunctionBegin;
12079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm,&pStart,&pEnd));
12089566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm,&ds));
12099566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
12109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm,0,&cStart,&cEnd));
12119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS));
12129566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS,&anchors));
12139566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec,&conStart,&conEnd));
12149566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&spdim));
12159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent));
12160c37af3bSToby Isaac 
12170c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
12180dd1b1feSToby Isaac     PetscObject       disc;
12190dd1b1feSToby Isaac     PetscClassId      id;
1220b3a4bf2aSToby Isaac     PetscSpace        bspace;
1221b3a4bf2aSToby Isaac     PetscDualSpace    dspace;
12229c3cf19fSMatthew G. Knepley     PetscInt          i, j, k, nPoints, Nc, offset;
122352a3aeb4SToby Isaac     PetscInt          fSize, maxDof;
1224b3a4bf2aSToby Isaac     PetscReal         *weights, *pointsRef, *pointsReal, *work;
12251683a169SBarry Smith     PetscScalar       *scwork;
12261683a169SBarry Smith     const PetscScalar *X;
12272c44ad04SToby Isaac     PetscInt          *sizes, *workIndRow, *workIndCol;
12280c37af3bSToby Isaac     Mat               Amat, Bmat, Xmat;
12292c44ad04SToby Isaac     const PetscInt    *numDof  = NULL;
1230085f0adfSToby Isaac     const PetscInt    ***perms = NULL;
1231085f0adfSToby Isaac     const PetscScalar ***flips = NULL;
12320c37af3bSToby Isaac 
12339566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds,f,&disc));
12349566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc,&id));
12350dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1236b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE) disc;
1237b3a4bf2aSToby Isaac 
12389566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe,&bspace));
12399566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(fe,&dspace));
12409566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace,&fSize));
12419566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe,&Nc));
12420dd1b1feSToby Isaac     }
12430dd1b1feSToby Isaac     else if (id == PETSCFV_CLASSID) {
1244b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV) disc;
1245b3a4bf2aSToby Isaac 
12469566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv,&Nc));
12479566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv),&bspace));
12489566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(bspace,PETSCSPACEPOLYNOMIAL));
12499566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetDegree(bspace,0,PETSC_DETERMINE));
12509566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(bspace,Nc));
12519566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(bspace,spdim));
12529566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(bspace));
12539566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv,&dspace));
12549566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace,&fSize));
12550dd1b1feSToby Isaac     }
125698921bdaSJacob Faibussowitsch     else SETERRQ(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
12579566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetNumDof(dspace,&numDof));
12582c44ad04SToby Isaac     for (i = 0, maxDof = 0; i <= spdim; i++) {maxDof = PetscMax(maxDof,numDof[i]);}
12599566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSymmetries(dspace,&perms,&flips));
12600dd1b1feSToby Isaac 
12619566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF,&Amat));
12629566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Amat,fSize,fSize,fSize,fSize));
12639566063dSJacob Faibussowitsch     PetscCall(MatSetType(Amat,MATSEQDENSE));
12649566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Amat));
12659566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat));
12669566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat));
12670c37af3bSToby Isaac     nPoints = 0;
12680c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
126952a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12700c37af3bSToby Isaac       PetscQuadrature quad;
12710c37af3bSToby Isaac 
12729566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace,i,&quad));
12739566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad,NULL,&thisNc,&qPoints,NULL,NULL));
127463a3b9bcSJacob Faibussowitsch       PetscCheck(thisNc == Nc,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT,thisNc,Nc);
12750c37af3bSToby Isaac       nPoints += qPoints;
12760c37af3bSToby Isaac     }
12779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(fSize,&sizes,nPoints*Nc,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal,nPoints*fSize*Nc,&work,maxDof,&workIndRow,maxDof,&workIndCol));
12789566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof * maxDof,&scwork));
12790c37af3bSToby Isaac     offset = 0;
12800c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12810c37af3bSToby Isaac       PetscInt        qPoints;
12820c37af3bSToby Isaac       const PetscReal    *p, *w;
12830c37af3bSToby Isaac       PetscQuadrature quad;
12840c37af3bSToby Isaac 
12859566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace,i,&quad));
12869566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad,NULL,NULL,&qPoints,&p,&w));
12879566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(weights+Nc*offset,w,Nc*qPoints));
12889566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pointsRef+spdim*offset,p,spdim*qPoints));
1289b3a4bf2aSToby Isaac       sizes[i] = qPoints;
12900c37af3bSToby Isaac       offset  += qPoints;
12910c37af3bSToby Isaac     }
12929566063dSJacob Faibussowitsch     PetscCall(EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsRef,weights,work,Amat));
12939566063dSJacob Faibussowitsch     PetscCall(MatLUFactor(Amat,NULL,NULL,NULL));
12940c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
12950c37af3bSToby Isaac       PetscInt        parent;
12960c37af3bSToby Isaac       PetscInt        closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
12970c37af3bSToby Isaac       PetscInt        *childOffsets, *parentOffsets;
12980c37af3bSToby Isaac 
12999566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,c,&parent,NULL));
13000c37af3bSToby Isaac       if (parent == c) continue;
13019566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure));
13020c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13030c37af3bSToby Isaac         PetscInt p = closure[2*i];
13040c37af3bSToby Isaac         PetscInt conDof;
13050c37af3bSToby Isaac 
13060c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1307085f0adfSToby Isaac         if (numFields) {
13089566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec,p,f,&conDof));
13090c37af3bSToby Isaac         }
13100c37af3bSToby Isaac         else {
13119566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec,p,&conDof));
13120c37af3bSToby Isaac         }
13130c37af3bSToby Isaac         if (conDof) break;
13140c37af3bSToby Isaac       }
13150c37af3bSToby Isaac       if (i == closureSize) {
13169566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure));
13170c37af3bSToby Isaac         continue;
13180c37af3bSToby Isaac       }
13190c37af3bSToby Isaac 
13209566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
13219566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
13220c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1323c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
1324c330f8ffSToby Isaac 
1325c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i*spdim],vtmp);
1326c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);
13270c37af3bSToby Isaac       }
13289566063dSJacob Faibussowitsch       PetscCall(EvaluateBasis(bspace,fSize,fSize,Nc,nPoints,sizes,pointsReal,weights,work,Bmat));
13299566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(Amat,Bmat,Xmat));
13309566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Xmat,&X));
13319566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP));
13329566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets));
13330c37af3bSToby Isaac       childOffsets[0] = 0;
13340c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13350c37af3bSToby Isaac         PetscInt p = closure[2*i];
13360c37af3bSToby Isaac         PetscInt dof;
13370c37af3bSToby Isaac 
1338085f0adfSToby Isaac         if (numFields) {
13399566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,p,f,&dof));
13400c37af3bSToby Isaac         }
13410c37af3bSToby Isaac         else {
13429566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,p,&dof));
13430c37af3bSToby Isaac         }
134452a3aeb4SToby Isaac         childOffsets[i+1]=childOffsets[i]+dof;
13450c37af3bSToby Isaac       }
13460c37af3bSToby Isaac       parentOffsets[0] = 0;
13470c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
13480c37af3bSToby Isaac         PetscInt p = closureP[2*i];
13490c37af3bSToby Isaac         PetscInt dof;
13500c37af3bSToby Isaac 
1351085f0adfSToby Isaac         if (numFields) {
13529566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,p,f,&dof));
13530c37af3bSToby Isaac         }
13540c37af3bSToby Isaac         else {
13559566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section,p,&dof));
13560c37af3bSToby Isaac         }
135752a3aeb4SToby Isaac         parentOffsets[i+1]=parentOffsets[i]+dof;
13580c37af3bSToby Isaac       }
13590c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
13602c44ad04SToby Isaac         PetscInt conDof, conOff, aDof, aOff, nWork;
13610c37af3bSToby Isaac         PetscInt p = closure[2*i];
13620c37af3bSToby Isaac         PetscInt o = closure[2*i+1];
1363085f0adfSToby Isaac         const PetscInt    *perm;
1364085f0adfSToby Isaac         const PetscScalar *flip;
13650c37af3bSToby Isaac 
13660c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1367085f0adfSToby Isaac         if (numFields) {
13689566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec,p,f,&conDof));
13699566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&conOff));
13700c37af3bSToby Isaac         }
13710c37af3bSToby Isaac         else {
13729566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec,p,&conDof));
13739566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cSec,p,&conOff));
13740c37af3bSToby Isaac         }
13750c37af3bSToby Isaac         if (!conDof) continue;
1376085f0adfSToby Isaac         perm  = (perms && perms[i]) ? perms[i][o] : NULL;
1377085f0adfSToby Isaac         flip  = (flips && flips[i]) ? flips[i][o] : NULL;
13789566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec,p,&aDof));
13799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,p,&aOff));
13802c44ad04SToby Isaac         nWork = childOffsets[i+1]-childOffsets[i];
13810c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13820c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13830c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13840c37af3bSToby Isaac 
1385085f0adfSToby Isaac           if (numFields) {
13869566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section,a,f,&aSecDof));
13879566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section,a,f,&aSecOff));
13880c37af3bSToby Isaac           }
13890c37af3bSToby Isaac           else {
13909566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section,a,&aSecDof));
13919566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section,a,&aSecOff));
13920c37af3bSToby Isaac           }
13930c37af3bSToby Isaac           if (!aSecDof) continue;
13940c37af3bSToby Isaac 
13950c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
13960c37af3bSToby Isaac             PetscInt q = closureP[2*j];
13970c37af3bSToby Isaac             PetscInt oq = closureP[2*j+1];
13982c44ad04SToby Isaac 
13992c44ad04SToby Isaac             if (q == a) {
140052a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1401085f0adfSToby Isaac               const PetscInt    *permP;
1402085f0adfSToby Isaac               const PetscScalar *flipP;
1403085f0adfSToby Isaac 
1404085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1405085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
14062c44ad04SToby Isaac               nWorkP = parentOffsets[j+1]-parentOffsets[j];
14072c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
14081683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
14092c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
14102c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
14112c44ad04SToby Isaac                 for (s = 0; s < nWorkP; s++) {
14122c44ad04SToby Isaac                   scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
14132c44ad04SToby Isaac                 }
14142c44ad04SToby Isaac               }
141552a3aeb4SToby Isaac               for (r = 0; r < nWork; r++)  {workIndRow[perm  ? perm[r]  : r] = conOff  + r;}
141652a3aeb4SToby Isaac               for (s = 0; s < nWorkP; s++) {workIndCol[permP ? permP[s] : s] = aSecOff + s;}
14172c44ad04SToby Isaac               if (flip) {
14182c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14192c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14202c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flip[r];
14212c44ad04SToby Isaac                   }
14222c44ad04SToby Isaac                 }
14232c44ad04SToby Isaac               }
14242c44ad04SToby Isaac               if (flipP) {
14252c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
14262c44ad04SToby Isaac                   for (s = 0; s < nWorkP; s++) {
14272c44ad04SToby Isaac                     scwork[r * nWorkP + s] *= flipP[s];
14282c44ad04SToby Isaac                   }
14292c44ad04SToby Isaac                 }
14302c44ad04SToby Isaac               }
14319566063dSJacob Faibussowitsch               PetscCall(MatSetValues(cMat,nWork,workIndRow,nWorkP,workIndCol,scwork,INSERT_VALUES));
14322c44ad04SToby Isaac               break;
14330c37af3bSToby Isaac             }
14340c37af3bSToby Isaac           }
14350c37af3bSToby Isaac         }
14360c37af3bSToby Isaac       }
14379566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Xmat,&X));
14389566063dSJacob Faibussowitsch       PetscCall(PetscFree2(childOffsets,parentOffsets));
14399566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure));
14409566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP));
14410c37af3bSToby Isaac     }
14429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Amat));
14439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Bmat));
14449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Xmat));
14459566063dSJacob Faibussowitsch     PetscCall(PetscFree(scwork));
14469566063dSJacob Faibussowitsch     PetscCall(PetscFree7(sizes,weights,pointsRef,pointsReal,work,workIndRow,workIndCol));
1447b3a4bf2aSToby Isaac     if (id == PETSCFV_CLASSID) {
14489566063dSJacob Faibussowitsch       PetscCall(PetscSpaceDestroy(&bspace));
1449b3a4bf2aSToby Isaac     }
14500c37af3bSToby Isaac   }
14519566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY));
14529566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY));
14539566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent));
14549566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
14550c37af3bSToby Isaac 
14560c37af3bSToby Isaac   PetscFunctionReturn(0);
14570c37af3bSToby Isaac }
145895a0b26dSToby Isaac 
145921968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
146095a0b26dSToby Isaac {
1461f7c74593SToby Isaac   Mat               refCmat;
146221968bf8SToby Isaac   PetscDS           ds;
1463085f0adfSToby Isaac   PetscInt          numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
146421968bf8SToby Isaac   PetscScalar       ***refPointFieldMats;
146521968bf8SToby Isaac   PetscSection      refConSec, refAnSec, refSection;
146621968bf8SToby Isaac   IS                refAnIS;
146721968bf8SToby Isaac   const PetscInt    *refAnchors;
1468085f0adfSToby Isaac   const PetscInt    **perms;
1469085f0adfSToby Isaac   const PetscScalar **flips;
147095a0b26dSToby Isaac 
147195a0b26dSToby Isaac   PetscFunctionBegin;
14729566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
14739566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
1474085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
14759566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,&refCmat,NULL));
14769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree,&refAnSec,&refAnIS));
14779566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(refAnIS,&refAnchors));
14789566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree,&refSection));
14799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
14809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats));
14819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN));
14829566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec,&maxDof));
14839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec,&maxAnDof));
14849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof,&rows));
14859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof*maxAnDof,&cols));
148695a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
148795a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
148895a0b26dSToby Isaac 
14899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree,p,&parent,NULL));
14909566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec,p,&pDof));
149195a0b26dSToby Isaac     if (!pDof || parent == p) continue;
149295a0b26dSToby Isaac 
14939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxFields,&refPointFieldMats[p-pRefStart]));
14949566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxFields,&refPointFieldN[p-pRefStart]));
14959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure));
1496085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1497085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
149895a0b26dSToby Isaac 
1499085f0adfSToby Isaac       if (f < numFields) {
15009566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
15019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec,p,f,&cOff));
15029566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips));
1503085f0adfSToby Isaac       } else {
15049566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec,p,&cDof));
15059566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec,p,&cOff));
15069566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetPointSyms(refSection,closureSize,closure,&perms,&flips));
150795a0b26dSToby Isaac       }
150895a0b26dSToby Isaac 
150995a0b26dSToby Isaac       for (r = 0; r < cDof; r++) {
151095a0b26dSToby Isaac         rows[r] = cOff + r;
151195a0b26dSToby Isaac       }
151295a0b26dSToby Isaac       numCols = 0;
151395a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
151495a0b26dSToby Isaac         PetscInt          q = closure[2*i];
151595a0b26dSToby Isaac         PetscInt          aDof, aOff, j;
1516085f0adfSToby Isaac         const PetscInt    *perm = perms ? perms[i] : NULL;
151795a0b26dSToby Isaac 
1518085f0adfSToby Isaac         if (numFields) {
15199566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection,q,f,&aDof));
15209566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection,q,f,&aOff));
152195a0b26dSToby Isaac         }
152295a0b26dSToby Isaac         else {
15239566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection,q,&aDof));
15249566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection,q,&aOff));
152595a0b26dSToby Isaac         }
152695a0b26dSToby Isaac 
152795a0b26dSToby Isaac         for (j = 0; j < aDof; j++) {
1528085f0adfSToby Isaac           cols[numCols++] = aOff + (perm ? perm[j] : j);
152995a0b26dSToby Isaac         }
153095a0b26dSToby Isaac       }
153195a0b26dSToby Isaac       refPointFieldN[p-pRefStart][f] = numCols;
15329566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]));
15339566063dSJacob Faibussowitsch       PetscCall(MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]));
1534085f0adfSToby Isaac       if (flips) {
1535085f0adfSToby Isaac         PetscInt colOff = 0;
1536085f0adfSToby Isaac 
1537085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1538085f0adfSToby Isaac           PetscInt          q = closure[2*i];
1539085f0adfSToby Isaac           PetscInt          aDof, aOff, j;
1540085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1541085f0adfSToby Isaac 
1542085f0adfSToby Isaac           if (numFields) {
15439566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(refSection,q,f,&aDof));
15449566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(refSection,q,f,&aOff));
1545085f0adfSToby Isaac           }
1546085f0adfSToby Isaac           else {
15479566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(refSection,q,&aDof));
15489566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(refSection,q,&aOff));
1549085f0adfSToby Isaac           }
1550085f0adfSToby Isaac           if (flip) {
1551085f0adfSToby Isaac             PetscInt k;
1552085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1553085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1554085f0adfSToby Isaac                 refPointFieldMats[p-pRefStart][f][k * numCols + colOff + j] *= flip[j];
1555085f0adfSToby Isaac               }
1556085f0adfSToby Isaac             }
1557085f0adfSToby Isaac           }
1558085f0adfSToby Isaac           colOff += aDof;
1559085f0adfSToby Isaac         }
1560085f0adfSToby Isaac       }
1561085f0adfSToby Isaac       if (numFields) {
15629566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestoreFieldPointSyms(refSection,f,closureSize,closure,&perms,&flips));
1563085f0adfSToby Isaac       } else {
15649566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestorePointSyms(refSection,closureSize,closure,&perms,&flips));
1565085f0adfSToby Isaac       }
156695a0b26dSToby Isaac     }
15679566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure));
156895a0b26dSToby Isaac   }
156921968bf8SToby Isaac   *childrenMats = refPointFieldMats;
157021968bf8SToby Isaac   *childrenN = refPointFieldN;
15719566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(refAnIS,&refAnchors));
15729566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
15739566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
157421968bf8SToby Isaac   PetscFunctionReturn(0);
157521968bf8SToby Isaac }
157621968bf8SToby Isaac 
157721968bf8SToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
157821968bf8SToby Isaac {
157921968bf8SToby Isaac   PetscDS        ds;
158021968bf8SToby Isaac   PetscInt       **refPointFieldN;
158121968bf8SToby Isaac   PetscScalar    ***refPointFieldMats;
1582085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
158321968bf8SToby Isaac   PetscSection   refConSec;
158421968bf8SToby Isaac 
158521968bf8SToby Isaac   PetscFunctionBegin;
158621968bf8SToby Isaac   refPointFieldN = *childrenN;
158721968bf8SToby Isaac   *childrenN = NULL;
158821968bf8SToby Isaac   refPointFieldMats = *childrenMats;
158921968bf8SToby Isaac   *childrenMats = NULL;
15909566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
15919566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
1592367003a6SStefano Zampini   maxFields = PetscMax(1,numFields);
15939566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
15949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
159521968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
159621968bf8SToby Isaac     PetscInt parent, pDof;
159721968bf8SToby Isaac 
15989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree,p,&parent,NULL));
15999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec,p,&pDof));
160021968bf8SToby Isaac     if (!pDof || parent == p) continue;
160121968bf8SToby Isaac 
1602085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
160321968bf8SToby Isaac       PetscInt cDof;
160421968bf8SToby Isaac 
1605085f0adfSToby Isaac       if (numFields) {
16069566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
160721968bf8SToby Isaac       }
160821968bf8SToby Isaac       else {
16099566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec,p,&cDof));
161021968bf8SToby Isaac       }
161121968bf8SToby Isaac 
16129566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
161321968bf8SToby Isaac     }
16149566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
16159566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
161621968bf8SToby Isaac   }
16179566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
16189566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldN));
161921968bf8SToby Isaac   PetscFunctionReturn(0);
162021968bf8SToby Isaac }
162121968bf8SToby Isaac 
162221968bf8SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
162321968bf8SToby Isaac {
162421968bf8SToby Isaac   DM             refTree;
162521968bf8SToby Isaac   PetscDS        ds;
162621968bf8SToby Isaac   Mat            refCmat;
1627085f0adfSToby Isaac   PetscInt       numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
162821968bf8SToby Isaac   PetscScalar ***refPointFieldMats, *pointWork;
162921968bf8SToby Isaac   PetscSection   refConSec, refAnSec, anSec;
163021968bf8SToby Isaac   IS             refAnIS, anIS;
163121968bf8SToby Isaac   const PetscInt *anchors;
163221968bf8SToby Isaac 
163321968bf8SToby Isaac   PetscFunctionBegin;
163421968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
16359566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm,&ds));
16369566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
1637085f0adfSToby Isaac   maxFields = PetscMax(1,numFields);
16389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm,&refTree));
16399566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm,refTree));
16409566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,&refCmat,NULL));
16419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree,&refAnSec,&refAnIS));
16429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm,&anSec,&anIS));
16439566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(anIS,&anchors));
16449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
16459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(conSec,&conStart,&conEnd));
16469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec,&maxDof));
16479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec,&maxAnDof));
16489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork));
164921968bf8SToby Isaac 
165021968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
16519566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
165295a0b26dSToby Isaac 
165395a0b26dSToby Isaac   /* step 2: compute the preorder */
16549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm,&pStart,&pEnd));
16559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm));
165695a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
165795a0b26dSToby Isaac     perm[p - pStart] = p;
165895a0b26dSToby Isaac     iperm[p - pStart] = p-pStart;
165995a0b26dSToby Isaac   }
166095a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
166195a0b26dSToby Isaac     PetscInt point = perm[p];
166295a0b26dSToby Isaac     PetscInt parent;
166395a0b26dSToby Isaac 
16649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm,point,&parent,NULL));
166595a0b26dSToby Isaac     if (parent == point) {
166695a0b26dSToby Isaac       p++;
166795a0b26dSToby Isaac     }
166895a0b26dSToby Isaac     else {
166995a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
167095a0b26dSToby Isaac 
16719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
167295a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
167395a0b26dSToby Isaac         PetscInt q = closure[2*i];
167495a0b26dSToby Isaac         if (iperm[q-pStart] > iperm[point-pStart]) {
167595a0b26dSToby Isaac           /* swap */
167695a0b26dSToby Isaac           perm[p]               = q;
167795a0b26dSToby Isaac           perm[iperm[q-pStart]] = point;
167895a0b26dSToby Isaac           iperm[point-pStart]   = iperm[q-pStart];
167995a0b26dSToby Isaac           iperm[q-pStart]       = p;
168095a0b26dSToby Isaac           break;
168195a0b26dSToby Isaac         }
168295a0b26dSToby Isaac       }
168395a0b26dSToby Isaac       size = closureSize;
16849566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
168595a0b26dSToby Isaac       if (i == size) {
168695a0b26dSToby Isaac         p++;
168795a0b26dSToby Isaac       }
168895a0b26dSToby Isaac     }
168995a0b26dSToby Isaac   }
169095a0b26dSToby Isaac 
169195a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
169295a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
169395a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
169495a0b26dSToby Isaac    * values outside of the Mat first.
169595a0b26dSToby Isaac    */
169695a0b26dSToby Isaac   {
169795a0b26dSToby Isaac     PetscInt nRows, row, nnz;
169895a0b26dSToby Isaac     PetscBool done;
169995a0b26dSToby Isaac     const PetscInt *ia, *ja;
170095a0b26dSToby Isaac     PetscScalar *vals;
170195a0b26dSToby Isaac 
17029566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done));
170328b400f6SJacob Faibussowitsch     PetscCheck(done,PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix");
170495a0b26dSToby Isaac     nnz  = ia[nRows];
170595a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
170695a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
17079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz,&vals));
170895a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
170995a0b26dSToby Isaac       PetscInt        parent, childid, closureSize, *closure = NULL;
171095a0b26dSToby Isaac       PetscInt        point = perm[p], pointDof;
171195a0b26dSToby Isaac 
17129566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,point,&parent,&childid));
171395a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
17149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(conSec,point,&pointDof));
171595a0b26dSToby Isaac       if (!pointDof) continue;
17169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
1717085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1718085f0adfSToby Isaac         PetscInt cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
171995a0b26dSToby Isaac         PetscScalar *pointMat;
1720085f0adfSToby Isaac         const PetscInt    **perms;
1721085f0adfSToby Isaac         const PetscScalar **flips;
172295a0b26dSToby Isaac 
1723085f0adfSToby Isaac         if (numFields) {
17249566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(conSec,point,f,&cDof));
17259566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(conSec,point,f,&cOff));
172695a0b26dSToby Isaac         }
172795a0b26dSToby Isaac         else {
17289566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(conSec,point,&cDof));
17299566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(conSec,point,&cOff));
173095a0b26dSToby Isaac         }
173195a0b26dSToby Isaac         if (!cDof) continue;
17329566063dSJacob Faibussowitsch         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section,f,closureSize,closure,&perms,&flips));
17339566063dSJacob Faibussowitsch         else           PetscCall(PetscSectionGetPointSyms(section,closureSize,closure,&perms,&flips));
173495a0b26dSToby Isaac 
173595a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
173676bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
173795a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
173895a0b26dSToby Isaac             if (cDof > 1 && r) {
173963a3b9bcSJacob Faibussowitsch               PetscCheck((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: %" PetscInt_FMT " vs. %" PetscInt_FMT, (ia[cOff+r+1]-ia[cOff+r]), (ia[cOff+r]-ia[cOff+r-1]));
174095a0b26dSToby Isaac             }
174195a0b26dSToby Isaac           }
174276bd3646SJed Brown         }
174395a0b26dSToby Isaac         /* zero rows */
174495a0b26dSToby Isaac         for (i = ia[cOff] ; i< ia[cOff+cDof];i++) {
174595a0b26dSToby Isaac           vals[i] = 0.;
174695a0b26dSToby Isaac         }
174795a0b26dSToby Isaac         matOffset = ia[cOff];
174895a0b26dSToby Isaac         numFillCols = ia[cOff+1] - matOffset;
174995a0b26dSToby Isaac         pointMat = refPointFieldMats[childid-pRefStart][f];
175095a0b26dSToby Isaac         numCols = refPointFieldN[childid-pRefStart][f];
175195a0b26dSToby Isaac         offset = 0;
175295a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
175395a0b26dSToby Isaac           PetscInt q = closure[2*i];
175495a0b26dSToby Isaac           PetscInt aDof, aOff, j, k, qConDof, qConOff;
1755085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1756085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
175795a0b26dSToby Isaac 
175895a0b26dSToby Isaac           qConDof = qConOff = 0;
1759085f0adfSToby Isaac           if (numFields) {
17609566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section,q,f,&aDof));
17619566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section,q,f,&aOff));
176295a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
17639566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(conSec,q,f,&qConDof));
17649566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldOffset(conSec,q,f,&qConOff));
176595a0b26dSToby Isaac             }
176695a0b26dSToby Isaac           }
176795a0b26dSToby Isaac           else {
17689566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section,q,&aDof));
17699566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section,q,&aOff));
177095a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
17719566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(conSec,q,&qConDof));
17729566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(conSec,q,&qConOff));
177395a0b26dSToby Isaac             }
177495a0b26dSToby Isaac           }
177595a0b26dSToby Isaac           if (!aDof) continue;
177695a0b26dSToby Isaac           if (qConDof) {
177795a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
177895a0b26dSToby Isaac              * be filled, thanks to preordering */
177995a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
178095a0b26dSToby Isaac             PetscInt aMatOffset = ia[qConOff];
178195a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
178295a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
178395a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
178495a0b26dSToby Isaac                 PetscScalar inVal = 0;
178595a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1786085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
178795a0b26dSToby Isaac 
1788085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
178995a0b26dSToby Isaac                 }
179095a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
179195a0b26dSToby Isaac               }
179295a0b26dSToby Isaac             }
179395a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
179495a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
179595a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
179695a0b26dSToby Isaac               for (;k < numFillCols; k++) {
179795a0b26dSToby Isaac                 if (ja[matOffset + k] == col) {
179895a0b26dSToby Isaac                   break;
179995a0b26dSToby Isaac                 }
180095a0b26dSToby Isaac               }
180163a3b9bcSJacob Faibussowitsch               PetscCheck(k != numFillCols,PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
180295a0b26dSToby Isaac               for (r = 0; r < cDof; r++) {
180395a0b26dSToby Isaac                 vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
180495a0b26dSToby Isaac               }
180595a0b26dSToby Isaac             }
180695a0b26dSToby Isaac           }
180795a0b26dSToby Isaac           else {
180895a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
180995a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
181095a0b26dSToby Isaac               if (ja[matOffset + k] == aOff) {
181195a0b26dSToby Isaac                 break;
181295a0b26dSToby Isaac               }
181395a0b26dSToby Isaac             }
181463a3b9bcSJacob Faibussowitsch             PetscCheck(k != numFillCols,PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
181595a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1816085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1817085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1818085f0adfSToby Isaac 
1819085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
182095a0b26dSToby Isaac               }
182195a0b26dSToby Isaac             }
182295a0b26dSToby Isaac           }
182395a0b26dSToby Isaac           offset += aDof;
182495a0b26dSToby Isaac         }
1825085f0adfSToby Isaac         if (numFields) {
18269566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestoreFieldPointSyms(section,f,closureSize,closure,&perms,&flips));
1827085f0adfSToby Isaac         } else {
18289566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestorePointSyms(section,closureSize,closure,&perms,&flips));
1829085f0adfSToby Isaac         }
183095a0b26dSToby Isaac       }
18319566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
183295a0b26dSToby Isaac     }
183395a0b26dSToby Isaac     for (row = 0; row < nRows; row++) {
18349566063dSJacob Faibussowitsch       PetscCall(MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES));
183595a0b26dSToby Isaac     }
18369566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done));
183728b400f6SJacob Faibussowitsch     PetscCheck(done,PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix");
18389566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY));
18399566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY));
18409566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
184195a0b26dSToby Isaac   }
184295a0b26dSToby Isaac 
184395a0b26dSToby Isaac   /* clean up */
18449566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(anIS,&anchors));
18459566063dSJacob Faibussowitsch   PetscCall(PetscFree2(perm,iperm));
18469566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointWork));
18479566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
184895a0b26dSToby Isaac   PetscFunctionReturn(0);
184995a0b26dSToby Isaac }
185095a0b26dSToby Isaac 
18516f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
18526f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
18536f5f1567SToby Isaac PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm)
18546f5f1567SToby Isaac {
18556f5f1567SToby Isaac   DM K;
1856420f55faSMatthew G. Knepley   PetscMPIInt rank;
18576f5f1567SToby Isaac   PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
18586f5f1567SToby Isaac   PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations;
18596f5f1567SToby Isaac   PetscInt *Kembedding;
18606f5f1567SToby Isaac   PetscInt *cellClosure=NULL, nc;
18616f5f1567SToby Isaac   PetscScalar *newVertexCoords;
18626f5f1567SToby Isaac   PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
18636f5f1567SToby Isaac   PetscSection parentSection;
18646f5f1567SToby Isaac 
18656f5f1567SToby Isaac   PetscFunctionBegin;
18669566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
18679566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dim));
18689566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
18699566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ncdm,dim));
18706f5f1567SToby Isaac 
18719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
18729566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection));
18739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm,&K));
18746858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1875dd400576SPatrick Sanan   if (rank == 0) {
18766f5f1567SToby Isaac     /* compute the new charts */
18779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd));
18786f5f1567SToby Isaac     offset = 0;
18796f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18806f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
18816f5f1567SToby Isaac 
18826f5f1567SToby Isaac       pNewStart[d] = offset;
18839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]));
18849566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K,d,&kStart,&kEnd));
18856f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
18866f5f1567SToby Isaac       /* adding the new points */
18876f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
18886f5f1567SToby Isaac       if (!d) {
18896f5f1567SToby Isaac         /* removing the cell */
18906f5f1567SToby Isaac         pNewCount[d]--;
18916f5f1567SToby Isaac       }
18926f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18936f5f1567SToby Isaac         PetscInt parent;
18949566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K,k,&parent,NULL));
18956f5f1567SToby Isaac         if (parent == k) {
18966f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
18976f5f1567SToby Isaac           pNewCount[d]--;
18986f5f1567SToby Isaac         }
18996f5f1567SToby Isaac       }
19006f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
19016f5f1567SToby Isaac       offset = pNewEnd[d];
19026f5f1567SToby Isaac 
19036f5f1567SToby Isaac     }
19041dca8a05SBarry Smith     PetscCheck(cell >= pOldStart[0] && cell < pOldEnd[0],PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"%" PetscInt_FMT " not in cell range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cell, pOldStart[0], pOldEnd[0]);
19056f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
19069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure));
19076f5f1567SToby Isaac 
19089566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pNewEnd[dim],&newConeSizes));
19096f5f1567SToby Isaac     {
1910b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
19116f5f1567SToby Isaac       PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
19126f5f1567SToby Isaac 
19139566063dSJacob Faibussowitsch       PetscCall(DMPlexGetChart(K,&kStart,&kEnd));
19149566063dSJacob Faibussowitsch       PetscCall(PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient));
19156f5f1567SToby Isaac 
19166f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19176f5f1567SToby Isaac         perm[k - kStart] = k;
19186f5f1567SToby Isaac         iperm [k - kStart] = k - kStart;
19196f5f1567SToby Isaac         preOrient[k - kStart] = 0;
19206f5f1567SToby Isaac       }
19216f5f1567SToby Isaac 
19229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK));
19236f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
19246f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2*j+1];
19256f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2*j+1];
19266f5f1567SToby Isaac         PetscInt p, q;
19276f5f1567SToby Isaac 
19286f5f1567SToby Isaac         p = closureK[2*j];
19296f5f1567SToby Isaac         q = cellClosure[2*j];
19309566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, p, &pct));
19319566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, q, &qct));
19326f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
19336f5f1567SToby Isaac           if (q >= pOldStart[d] && q < pOldEnd[d]) {
19346f5f1567SToby Isaac             Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
19356f5f1567SToby Isaac           }
19366f5f1567SToby Isaac         }
1937b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1938b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
19396f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
19406f5f1567SToby Isaac           PetscInt numChildren, i;
19416f5f1567SToby Isaac           const PetscInt *children;
19426f5f1567SToby Isaac 
19439566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(K,p,&numChildren,&children));
19446f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
19456f5f1567SToby Isaac             PetscInt kPerm, oPerm;
19466f5f1567SToby Isaac 
19476f5f1567SToby Isaac             k    = children[i];
19489566063dSJacob Faibussowitsch             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm));
19496f5f1567SToby Isaac             /* perm = what refTree position I'm in */
19506f5f1567SToby Isaac             perm[kPerm-kStart]      = k;
19516f5f1567SToby Isaac             /* iperm = who is at this position */
19526f5f1567SToby Isaac             iperm[k-kStart]         = kPerm-kStart;
19536f5f1567SToby Isaac             preOrient[kPerm-kStart] = oPerm;
19546f5f1567SToby Isaac           }
19556f5f1567SToby Isaac         }
19566f5f1567SToby Isaac       }
19579566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK));
19586f5f1567SToby Isaac     }
19599566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection,0,pNewEnd[dim]));
19606f5f1567SToby Isaac     offset = 0;
19616f5f1567SToby Isaac     numNewCones = 0;
19626f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19636f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
19646f5f1567SToby Isaac       PetscInt p;
19656f5f1567SToby Isaac       PetscInt size;
19666f5f1567SToby Isaac 
19676f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19686f5f1567SToby Isaac         /* skip cell 0 */
19696f5f1567SToby Isaac         if (p == cell) continue;
19706f5f1567SToby Isaac         /* old cones to new cones */
19719566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm,p,&size));
19726f5f1567SToby Isaac         newConeSizes[offset++] = size;
19736f5f1567SToby Isaac         numNewCones += size;
19746f5f1567SToby Isaac       }
19756f5f1567SToby Isaac 
19769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K,d,&kStart,&kEnd));
19776f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19786f5f1567SToby Isaac         PetscInt kParent;
19796f5f1567SToby Isaac 
19809566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K,k,&kParent,NULL));
19816f5f1567SToby Isaac         if (kParent != k) {
19826f5f1567SToby Isaac           Kembedding[k] = offset;
19839566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K,k,&size));
19846f5f1567SToby Isaac           newConeSizes[offset++] = size;
19856f5f1567SToby Isaac           numNewCones += size;
19866f5f1567SToby Isaac           if (kParent != 0) {
19879566063dSJacob Faibussowitsch             PetscCall(PetscSectionSetDof(parentSection,Kembedding[k],1));
19886f5f1567SToby Isaac           }
19896f5f1567SToby Isaac         }
19906f5f1567SToby Isaac       }
19916f5f1567SToby Isaac     }
19926f5f1567SToby Isaac 
19939566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
19949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(parentSection,&numPointsWithParents));
19959566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations));
19969566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs));
19976f5f1567SToby Isaac 
19986f5f1567SToby Isaac     /* fill new cones */
19996f5f1567SToby Isaac     offset = 0;
20006f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20016f5f1567SToby Isaac       PetscInt kStart, kEnd, k, l;
20026f5f1567SToby Isaac       PetscInt p;
20036f5f1567SToby Isaac       PetscInt size;
20046f5f1567SToby Isaac       const PetscInt *cone, *orientation;
20056f5f1567SToby Isaac 
20066f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
20076f5f1567SToby Isaac         /* skip cell 0 */
20086f5f1567SToby Isaac         if (p == cell) continue;
20096f5f1567SToby Isaac         /* old cones to new cones */
20109566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm,p,&size));
20119566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm,p,&cone));
20129566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeOrientation(dm,p,&orientation));
20136f5f1567SToby Isaac         for (l = 0; l < size; l++) {
20146f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
20156f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
20166f5f1567SToby Isaac         }
20176f5f1567SToby Isaac       }
20186f5f1567SToby Isaac 
20199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K,d,&kStart,&kEnd));
20206f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
20216f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
20226f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
20236f5f1567SToby Isaac 
20249566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K,k,&kParent,NULL));
20256f5f1567SToby Isaac         if (kParent != k) {
20266f5f1567SToby Isaac           /* embed new cones */
20279566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K,k,&size));
20289566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(K,kPerm,&cone));
20299566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeOrientation(K,kPerm,&orientation));
20306f5f1567SToby Isaac           for (l = 0; l < size; l++) {
20316f5f1567SToby Isaac             PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size);
20326f5f1567SToby Isaac             PetscInt newO, lSize, oTrue;
2033b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
20346f5f1567SToby Isaac 
20356f5f1567SToby Isaac             q                         = iperm[cone[m]];
20366f5f1567SToby Isaac             newCones[offset]          = Kembedding[q];
20379566063dSJacob Faibussowitsch             PetscCall(DMPlexGetConeSize(K,q,&lSize));
2038b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
2039b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
2040b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
20416f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
20426f5f1567SToby Isaac             newO                      = DihedralCompose(lSize,oTrue,preOrient[q]);
2043b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
20446f5f1567SToby Isaac           }
20456f5f1567SToby Isaac           if (kParent != 0) {
20466f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
20479566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset));
20486f5f1567SToby Isaac             parents[pOffset]  = newPoint;
20496f5f1567SToby Isaac             childIDs[pOffset] = k;
20506f5f1567SToby Isaac           }
20516f5f1567SToby Isaac         }
20526f5f1567SToby Isaac       }
20536f5f1567SToby Isaac     }
20546f5f1567SToby Isaac 
20559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords));
20566f5f1567SToby Isaac 
20576f5f1567SToby Isaac     /* fill coordinates */
20586f5f1567SToby Isaac     offset = 0;
20596f5f1567SToby Isaac     {
2060d90620a3SMatthew G. Knepley       PetscInt kStart, kEnd, l;
20616f5f1567SToby Isaac       PetscSection vSection;
20626f5f1567SToby Isaac       PetscInt v;
20636f5f1567SToby Isaac       Vec coords;
20646f5f1567SToby Isaac       PetscScalar *coordvals;
20656f5f1567SToby Isaac       PetscInt dof, off;
2066c111c6b7SMatthew G. Knepley       PetscReal v0[3], J[9], detJ;
20676f5f1567SToby Isaac 
206876bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
2069d90620a3SMatthew G. Knepley         PetscInt k;
20709566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(K,0,&kStart,&kEnd));
20716f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
20729566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
207363a3b9bcSJacob Faibussowitsch           PetscCheck(detJ > 0.,PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %" PetscInt_FMT " has bad determinant",k);
20746f5f1567SToby Isaac         }
2075d90620a3SMatthew G. Knepley       }
20769566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
20779566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm,&vSection));
20789566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm,&coords));
20799566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords,&coordvals));
20806f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
20816f5f1567SToby Isaac 
20829566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(vSection,v,&dof));
20839566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(vSection,v,&off));
20846f5f1567SToby Isaac         for (l = 0; l < dof; l++) {
20856f5f1567SToby Isaac           newVertexCoords[offset++] = coordvals[off + l];
20866f5f1567SToby Isaac         }
20876f5f1567SToby Isaac       }
20889566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords,&coordvals));
20896f5f1567SToby Isaac 
20909566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(K,&vSection));
20919566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(K,&coords));
20929566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords,&coordvals));
20939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(K,0,&kStart,&kEnd));
20946f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
20959bc368c7SMatthew G. Knepley         PetscReal coord[3], newCoord[3];
20966f5f1567SToby Isaac         PetscInt  vPerm = perm[v];
20976f5f1567SToby Isaac         PetscInt  kParent;
2098c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1.,-1.,-1.};
20996f5f1567SToby Isaac 
21009566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K,v,&kParent,NULL));
21016f5f1567SToby Isaac         if (kParent != v) {
21026f5f1567SToby Isaac           /* this is a new vertex */
21039566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(vSection,vPerm,&off));
21049bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]);
2105367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
21069bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l];
21076f5f1567SToby Isaac           offset += dim;
21086f5f1567SToby Isaac         }
21096f5f1567SToby Isaac       }
21109566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords,&coordvals));
21116f5f1567SToby Isaac     }
21126f5f1567SToby Isaac 
21136f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
21146f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
21156f5f1567SToby Isaac       PetscInt tmp;
21166f5f1567SToby Isaac 
21176f5f1567SToby Isaac       tmp = pNewCount[d];
21186f5f1567SToby Isaac       pNewCount[d] = pNewCount[dim - d];
21196f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
21206f5f1567SToby Isaac     }
21216f5f1567SToby Isaac 
21229566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords));
21239566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm,K));
21249566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm,parentSection,parents,childIDs));
21256f5f1567SToby Isaac 
21266f5f1567SToby Isaac     /* clean up */
21279566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure));
21289566063dSJacob Faibussowitsch     PetscCall(PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd));
21299566063dSJacob Faibussowitsch     PetscCall(PetscFree(newConeSizes));
21309566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCones,newOrientations));
21319566063dSJacob Faibussowitsch     PetscCall(PetscFree(newVertexCoords));
21329566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parents,childIDs));
21339566063dSJacob Faibussowitsch     PetscCall(PetscFree4(Kembedding,perm,iperm,preOrient));
21346f5f1567SToby Isaac   }
21356f5f1567SToby Isaac   else {
21366f5f1567SToby Isaac     PetscInt    p, counts[4];
21376f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
21386f5f1567SToby Isaac     Vec         coordVec;
21396f5f1567SToby Isaac     PetscScalar *coords;
21406f5f1567SToby Isaac 
21416f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
21426f5f1567SToby Isaac       PetscInt dStart, dEnd;
21436f5f1567SToby Isaac 
21449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm,d,&dStart,&dEnd));
21456f5f1567SToby Isaac       counts[d] = dEnd - dStart;
21466f5f1567SToby Isaac     }
21479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEnd-pStart,&coneSizes));
21486f5f1567SToby Isaac     for (p = pStart; p < pEnd; p++) {
21499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]));
21506f5f1567SToby Isaac     }
21519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCones(dm, &cones));
21529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
21539566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm,&coordVec));
21549566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordVec,&coords));
21556f5f1567SToby Isaac 
21569566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection,pStart,pEnd));
21579566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
21589566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL));
21599566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm,K));
21609566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm,parentSection,NULL,NULL));
21619566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordVec,&coords));
21626f5f1567SToby Isaac   }
21639566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
21646f5f1567SToby Isaac 
21656f5f1567SToby Isaac   PetscFunctionReturn(0);
21666f5f1567SToby Isaac }
21676ecaa68aSToby Isaac 
21686ecaa68aSToby Isaac PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
21696ecaa68aSToby Isaac {
21706ecaa68aSToby Isaac   PetscSF           coarseToFineEmbedded;
21716ecaa68aSToby Isaac   PetscSection      globalCoarse, globalFine;
21726ecaa68aSToby Isaac   PetscSection      localCoarse, localFine;
21736ecaa68aSToby Isaac   PetscSection      aSec, cSec;
21746ecaa68aSToby Isaac   PetscSection      rootIndicesSec, rootMatricesSec;
217546bdb399SToby Isaac   PetscSection      leafIndicesSec, leafMatricesSec;
217646bdb399SToby Isaac   PetscInt          *rootIndices, *leafIndices;
217746bdb399SToby Isaac   PetscScalar       *rootMatrices, *leafMatrices;
21786ecaa68aSToby Isaac   IS                aIS;
21796ecaa68aSToby Isaac   const PetscInt    *anchors;
21806ecaa68aSToby Isaac   Mat               cMat;
21814acb8e1eSToby Isaac   PetscInt          numFields, maxFields;
21826ecaa68aSToby Isaac   PetscInt          pStartC, pEndC, pStartF, pEndF, p;
21836ecaa68aSToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
21841c58ffc4SToby Isaac   PetscInt          *maxChildIds;
2185e44e4e7fSToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
21864acb8e1eSToby Isaac   const PetscInt    ***perms;
21874acb8e1eSToby Isaac   const PetscScalar ***flips;
21886ecaa68aSToby Isaac 
21896ecaa68aSToby Isaac   PetscFunctionBegin;
21909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
21919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
21929566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
21936ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
219489698031SToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
219589698031SToby Isaac     const PetscInt *leaves;
21966ecaa68aSToby Isaac 
21979566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL));
219889698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
219989698031SToby Isaac       p = leaves ? leaves[l] : l;
22009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
22019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
22026ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
22036ecaa68aSToby Isaac         numPointsWithDofs++;
22046ecaa68aSToby Isaac       }
22056ecaa68aSToby Isaac     }
22069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
22077cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
220889698031SToby Isaac       p = leaves ? leaves[l] : l;
22099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
22109566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
22116ecaa68aSToby Isaac       if ((dof - cdof) > 0) {
221289698031SToby Isaac         pointsWithDofs[offset++] = l;
22136ecaa68aSToby Isaac       }
22146ecaa68aSToby Isaac     }
22159566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
22169566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
22176ecaa68aSToby Isaac   }
22186ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
22199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC-pStartC,&maxChildIds));
22206ecaa68aSToby Isaac   for (p = pStartC; p < pEndC; p++) {
22218d2f55e7SToby Isaac     maxChildIds[p - pStartC] = -2;
22226ecaa68aSToby Isaac   }
2223*57168dbeSPierre Jolivet   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPI_MAX));
2224*57168dbeSPierre Jolivet   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPI_MAX));
222546bdb399SToby Isaac 
22269566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
22279566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
222846bdb399SToby Isaac 
22299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse,&aSec,&aIS));
22309566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS,&anchors));
22319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd));
223246bdb399SToby Isaac 
22339566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse,&cSec,&cMat,NULL));
22349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec,&cStart,&cEnd));
223546bdb399SToby Isaac 
223646bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
22379566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec));
22389566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec));
22399566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootIndicesSec,pStartC,pEndC));
22409566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootMatricesSec,pStartC,pEndC));
22419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse,&numFields));
2242713c1c5dSToby Isaac   maxFields = PetscMax(1,numFields);
22439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc7(maxFields+1,&offsets,maxFields+1,&offsetsCopy,maxFields+1,&newOffsets,maxFields+1,&newOffsetsCopy,maxFields+1,&rowOffsets,maxFields+1,&numD,maxFields+1,&numO));
22449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxFields+1,(PetscInt****)&perms,maxFields+1,(PetscScalar****)&flips));
22459566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *) perms, (maxFields+1) * sizeof(const PetscInt **)));
22469566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *) flips, (maxFields+1) * sizeof(const PetscScalar **)));
224746bdb399SToby Isaac 
224846bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
22498d2f55e7SToby Isaac     PetscInt dof, matSize   = 0;
22506ecaa68aSToby Isaac     PetscInt aDof           = 0;
22516ecaa68aSToby Isaac     PetscInt cDof           = 0;
22526ecaa68aSToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
22536ecaa68aSToby Isaac     PetscInt numRowIndices  = 0;
22546ecaa68aSToby Isaac     PetscInt numColIndices  = 0;
2255f13f9184SToby Isaac     PetscInt f;
22566ecaa68aSToby Isaac 
22579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
22581cfc5b76SToby Isaac     if (dof < 0) {
22591cfc5b76SToby Isaac       dof = -(dof + 1);
22601cfc5b76SToby Isaac     }
22616ecaa68aSToby Isaac     if (p >= aStart && p < aEnd) {
22629566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(aSec,p,&aDof));
22636ecaa68aSToby Isaac     }
22646ecaa68aSToby Isaac     if (p >= cStart && p < cEnd) {
22659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cSec,p,&cDof));
22666ecaa68aSToby Isaac     }
2267f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2268f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
22696ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2270f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
22716ecaa68aSToby Isaac 
22729566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
227346bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
22746ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
22756ecaa68aSToby Isaac 
22769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse,c,&clDof));
22776ecaa68aSToby Isaac         numRowIndices += clDof;
22786ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
22799566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse,c,f,&clDof));
22806ecaa68aSToby Isaac           offsets[f + 1] += clDof;
22816ecaa68aSToby Isaac         }
22826ecaa68aSToby Isaac       }
22836ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
22846ecaa68aSToby Isaac         offsets[f + 1]   += offsets[f];
22856ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
22866ecaa68aSToby Isaac       }
228746bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
22889566063dSJacob Faibussowitsch       PetscCall(DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE));
22899566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
22906ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
22916ecaa68aSToby Isaac         numColIndices = numRowIndices;
22926ecaa68aSToby Isaac         matSize = 0;
22936ecaa68aSToby Isaac       }
229446bdb399SToby Isaac       else if (numFields) { /* we send one submat for each field: sum their sizes */
22956ecaa68aSToby Isaac         matSize = 0;
22966ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
22976ecaa68aSToby Isaac           PetscInt numRow, numCol;
22986ecaa68aSToby Isaac 
22996ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2300f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
23016ecaa68aSToby Isaac           matSize += numRow * numCol;
23026ecaa68aSToby Isaac         }
23036ecaa68aSToby Isaac       }
23046ecaa68aSToby Isaac       else {
23056ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
23066ecaa68aSToby Isaac       }
2307f13f9184SToby Isaac     } else if (maxChildId == -1) {
23088d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2309f13f9184SToby Isaac         PetscInt aOff, a;
23106ecaa68aSToby Isaac 
23119566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,p,&aOff));
23126ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
23136ecaa68aSToby Isaac           PetscInt fDof;
23146ecaa68aSToby Isaac 
23159566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
231621968bf8SToby Isaac           offsets[f+1] = fDof;
23176ecaa68aSToby Isaac         }
23186ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
23196ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
23206ecaa68aSToby Isaac 
23219566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(localCoarse,anchor,&aLocalDof));
23226ecaa68aSToby Isaac           numColIndices += aLocalDof;
23236ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23246ecaa68aSToby Isaac             PetscInt fDof;
23256ecaa68aSToby Isaac 
23269566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof));
232721968bf8SToby Isaac             newOffsets[f+1] += fDof;
23286ecaa68aSToby Isaac           }
23296ecaa68aSToby Isaac         }
23306ecaa68aSToby Isaac         if (numFields) {
23316ecaa68aSToby Isaac           matSize = 0;
23326ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
233321968bf8SToby Isaac             matSize += offsets[f+1] * newOffsets[f+1];
23346ecaa68aSToby Isaac           }
23356ecaa68aSToby Isaac         }
23366ecaa68aSToby Isaac         else {
23376ecaa68aSToby Isaac           matSize = numColIndices * dof;
23386ecaa68aSToby Isaac         }
23396ecaa68aSToby Isaac       }
23406ecaa68aSToby Isaac       else { /* no children, and no constraints on dofs: just get the global indices */
23416ecaa68aSToby Isaac         numColIndices = dof;
23426ecaa68aSToby Isaac         matSize       = 0;
23436ecaa68aSToby Isaac       }
23448d2f55e7SToby Isaac     }
234546bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
23469566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0));
23479566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootMatricesSec,p,matSize));
23486ecaa68aSToby Isaac   }
23499566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootIndicesSec));
23509566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootMatricesSec));
23516ecaa68aSToby Isaac   {
23526ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
23536ecaa68aSToby Isaac 
23549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices));
23559566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices));
23569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices));
23576ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
23586ecaa68aSToby Isaac       PetscInt    numRowIndices, numColIndices, matSize, dof;
2359f13f9184SToby Isaac       PetscInt    pIndOff, pMatOff, f;
23606ecaa68aSToby Isaac       PetscInt    *pInd;
23616ecaa68aSToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
23626ecaa68aSToby Isaac       PetscScalar *pMat = NULL;
23636ecaa68aSToby Isaac 
23649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec,p,&numColIndices));
23656ecaa68aSToby Isaac       if (!numColIndices) {
23666ecaa68aSToby Isaac         continue;
23676ecaa68aSToby Isaac       }
2368f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2369f13f9184SToby Isaac         offsets[f]        = 0;
2370f13f9184SToby Isaac         newOffsets[f]     = 0;
2371f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2372f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2373f13f9184SToby Isaac       }
23746ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
23759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec,p,&pIndOff));
23766ecaa68aSToby Isaac       pInd = &(rootIndices[pIndOff]);
23779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootMatricesSec,p,&matSize));
23786ecaa68aSToby Isaac       if (matSize) {
23799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootMatricesSec,p,&pMatOff));
23806ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
23816ecaa68aSToby Isaac       }
23829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
23831cfc5b76SToby Isaac       if (dof < 0) {
23841cfc5b76SToby Isaac         dof = -(dof + 1);
23851cfc5b76SToby Isaac       }
23866ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
23876ecaa68aSToby Isaac         PetscInt i, j;
23886ecaa68aSToby Isaac         PetscInt numRowIndices = matSize / numColIndices;
23896ecaa68aSToby Isaac 
23906ecaa68aSToby Isaac         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
23916ecaa68aSToby Isaac           PetscInt numIndices, *indices;
23929566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,PETSC_TRUE,&numIndices,&indices,offsets,NULL));
239308401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices,PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations");
23946ecaa68aSToby Isaac           for (i = 0; i < numColIndices; i++) {
23956ecaa68aSToby Isaac             pInd[i] = indices[i];
23966ecaa68aSToby Isaac           }
23976ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
239846bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i+1];
239946bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i+1];
24006ecaa68aSToby Isaac           }
24019566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,PETSC_TRUE,&numIndices,&indices,offsets,NULL));
24026ecaa68aSToby Isaac         }
24036ecaa68aSToby Isaac         else {
24046ecaa68aSToby Isaac           PetscInt closureSize, *closure = NULL, cl;
24056ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
24066ecaa68aSToby Isaac           PetscInt numPoints,*points;
24076ecaa68aSToby Isaac 
24089566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse,numRowIndices * numRowIndices,MPIU_SCALAR,&pMatIn));
24096ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
24106ecaa68aSToby Isaac             for (j = 0; j < numRowIndices; j++) {
24116ecaa68aSToby Isaac               pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
24126ecaa68aSToby Isaac             }
24136ecaa68aSToby Isaac           }
24149566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
24154acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24169566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]));
24179566063dSJacob Faibussowitsch             else           PetscCall(PetscSectionGetPointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]));
24184acb8e1eSToby Isaac           }
24196ecaa68aSToby Isaac           if (numFields) {
24206ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
24216ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
24226ecaa68aSToby Isaac 
24236ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
24246ecaa68aSToby Isaac                 PetscInt fDof;
24256ecaa68aSToby Isaac 
24269566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse,c,f,&fDof));
24276ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
24286ecaa68aSToby Isaac               }
24296ecaa68aSToby Isaac             }
24306ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
24316ecaa68aSToby Isaac               offsets[f + 1]   += offsets[f];
24326ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
24336ecaa68aSToby Isaac             }
24346ecaa68aSToby Isaac           }
24354acb8e1eSToby Isaac           /* TODO : flips here ? */
24366ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
24379566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,perms,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE));
24384acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24399566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse,f,closureSize,closure,&perms[f],&flips[f]));
24409566063dSJacob Faibussowitsch             else           PetscCall(PetscSectionRestorePointSyms(localCoarse,closureSize,closure,&perms[f],&flips[f]));
24414acb8e1eSToby Isaac           }
24424acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24439566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]));
24449566063dSJacob Faibussowitsch             else           PetscCall(PetscSectionGetPointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]));
24454acb8e1eSToby Isaac           }
24466ecaa68aSToby Isaac           if (!numFields) {
24476ecaa68aSToby Isaac             for (i = 0; i < numRowIndices * numColIndices; i++) {
24486ecaa68aSToby Isaac               pMat[i] = pMatModified[i];
24496ecaa68aSToby Isaac             }
24506ecaa68aSToby Isaac           }
24516ecaa68aSToby Isaac           else {
2452f13f9184SToby Isaac             PetscInt i, j, count;
24536ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
24546ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f+1]; i++) {
24556ecaa68aSToby Isaac                 for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) {
24566ecaa68aSToby Isaac                   pMat[count] = pMatModified[i * numColIndices + j];
24576ecaa68aSToby Isaac                 }
24586ecaa68aSToby Isaac               }
24596ecaa68aSToby Isaac             }
24606ecaa68aSToby Isaac           }
24619566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatModified));
24629566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
24639566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse,numRowIndices * numColIndices,MPIU_SCALAR,&pMatIn));
24646ecaa68aSToby Isaac           if (numFields) {
246546bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
246646bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f+1];
246746bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f+1];
24686ecaa68aSToby Isaac             }
24694acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24704acb8e1eSToby Isaac               PetscInt globalOff, c = points[2*cl];
24719566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
24729566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
24736ecaa68aSToby Isaac             }
24746ecaa68aSToby Isaac           } else {
24754acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
24764acb8e1eSToby Isaac               PetscInt c = points[2*cl], globalOff;
24774acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
24784acb8e1eSToby Isaac 
24799566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
24809566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
24816ecaa68aSToby Isaac             }
24826ecaa68aSToby Isaac           }
24834acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
24849566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse,f,numPoints,points,&perms[f],&flips[f]));
24859566063dSJacob Faibussowitsch             else           PetscCall(PetscSectionRestorePointSyms(localCoarse,numPoints,points,&perms[f],&flips[f]));
24864acb8e1eSToby Isaac           }
24879566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse,numPoints,MPIU_SCALAR,&points));
24886ecaa68aSToby Isaac         }
24896ecaa68aSToby Isaac       }
24906ecaa68aSToby Isaac       else if (matSize) {
24916ecaa68aSToby Isaac         PetscInt cOff;
24926ecaa68aSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof, aOff;
24936ecaa68aSToby Isaac 
24946ecaa68aSToby Isaac         numRowIndices = matSize / numColIndices;
249508401ef6SPierre Jolivet         PetscCheck(numRowIndices == dof,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs");
24969566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices));
24979566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse,numColIndices,MPIU_INT,&colIndices));
24989566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec,p,&cOff));
24999566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec,p,&aDof));
25009566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec,p,&aOff));
25016ecaa68aSToby Isaac         if (numFields) {
25026ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25036ecaa68aSToby Isaac             PetscInt fDof;
2504f13f9184SToby Isaac 
25059566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec,p,f,&fDof));
25066ecaa68aSToby Isaac             offsets[f + 1] = fDof;
25076ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
25086ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
25099566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof));
25106ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
25116ecaa68aSToby Isaac             }
25126ecaa68aSToby Isaac           }
25136ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25146ecaa68aSToby Isaac             offsets[f + 1]       += offsets[f];
25156ecaa68aSToby Isaac             offsetsCopy[f + 1]    = offsets[f + 1];
25166ecaa68aSToby Isaac             newOffsets[f + 1]    += newOffsets[f];
25176ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
25186ecaa68aSToby Isaac           }
25199566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec,PETSC_TRUE,p,cOff,offsetsCopy,PETSC_TRUE,NULL,-1, NULL,rowIndices));
25206ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25216ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25229566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse,anchor,&lOff));
25239566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_TRUE,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL,-1, NULL,colIndices));
25246ecaa68aSToby Isaac           }
25256ecaa68aSToby Isaac         }
25266ecaa68aSToby Isaac         else {
25279566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec,PETSC_TRUE,p,cOff,offsetsCopy,PETSC_TRUE,NULL, NULL,rowIndices));
25286ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25296ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
25309566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse,anchor,&lOff));
25319566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_TRUE,anchor,lOff,newOffsetsCopy,PETSC_TRUE,NULL, NULL,colIndices));
25326ecaa68aSToby Isaac           }
25336ecaa68aSToby Isaac         }
25346ecaa68aSToby Isaac         if (numFields) {
2535f13f9184SToby Isaac           PetscInt count, a;
2536f13f9184SToby Isaac 
25376ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
25386ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
25396ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
25409566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]));
25416ecaa68aSToby Isaac             count += iSize * jSize;
254246bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
254346bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f+1];
25446ecaa68aSToby Isaac           }
25456ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25466ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25476ecaa68aSToby Isaac             PetscInt gOff;
25489566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse,anchor,&gOff));
25499566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL,-1, NULL,pInd));
25506ecaa68aSToby Isaac           }
25516ecaa68aSToby Isaac         }
25526ecaa68aSToby Isaac         else {
25536ecaa68aSToby Isaac           PetscInt a;
25549566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat));
25556ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
25566ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
25576ecaa68aSToby Isaac             PetscInt gOff;
25589566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse,anchor,&gOff));
25599566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,NULL, NULL,pInd));
25606ecaa68aSToby Isaac           }
25616ecaa68aSToby Isaac         }
25629566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse,numColIndices,MPIU_INT,&colIndices));
25639566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse,numRowIndices,MPIU_INT,&rowIndices));
25646ecaa68aSToby Isaac       }
25656ecaa68aSToby Isaac       else {
25666ecaa68aSToby Isaac         PetscInt gOff;
25676ecaa68aSToby Isaac 
25689566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse,p,&gOff));
25696ecaa68aSToby Isaac         if (numFields) {
25706ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
25716ecaa68aSToby Isaac             PetscInt fDof;
25729566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
25736ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
25746ecaa68aSToby Isaac           }
25756ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
257646bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f+1];
257746bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f+1];
25786ecaa68aSToby Isaac           }
25799566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd));
2580367003a6SStefano Zampini         } else {
25819566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd));
25826ecaa68aSToby Isaac         }
25836ecaa68aSToby Isaac       }
25846ecaa68aSToby Isaac     }
25859566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
25866ecaa68aSToby Isaac   }
258746bdb399SToby Isaac   {
258846bdb399SToby Isaac     PetscSF  indicesSF, matricesSF;
258946bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
259046bdb399SToby Isaac 
25919566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec));
25929566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec));
25939566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec));
25949566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec));
25959566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF));
25969566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF));
25979566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
25989566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
25999566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
26009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices));
26019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices));
26029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices));
26039566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices,MPI_REPLACE));
26049566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices,MPI_REPLACE));
26059566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices,MPI_REPLACE));
26069566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices,MPI_REPLACE));
26079566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
26089566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
26099566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices,rootMatrices));
26109566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
26119566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
261246bdb399SToby Isaac   }
261346bdb399SToby Isaac   /* count to preallocate */
26149566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
261546bdb399SToby Isaac   {
261646bdb399SToby Isaac     PetscInt    nGlobal;
261746bdb399SToby Isaac     PetscInt    *dnnz, *onnz;
2618b9a5774bSToby Isaac     PetscLayout rowMap, colMap;
2619b9a5774bSToby Isaac     PetscInt    rowStart, rowEnd, colStart, colEnd;
26201c58ffc4SToby Isaac     PetscInt    maxDof;
26211c58ffc4SToby Isaac     PetscInt    *rowIndices;
26221c58ffc4SToby Isaac     DM           refTree;
26231c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
26241c58ffc4SToby Isaac     PetscScalar  ***refPointFieldMats;
26251c58ffc4SToby Isaac     PetscSection refConSec, refAnSec;
26260eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd;
26271c58ffc4SToby Isaac     PetscScalar  *pointWork;
262846bdb399SToby Isaac 
26299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal));
26309566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz));
26319566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat,&rowMap,&colMap));
26329566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
26339566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
26349566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap,&rowStart,&rowEnd));
26359566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap,&colStart,&colEnd));
26369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine,&maxDof));
26379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd));
26389566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
26390eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
264046bdb399SToby Isaac       PetscInt    gDof, gcDof, gOff;
264146bdb399SToby Isaac       PetscInt    numColIndices, pIndOff, *pInd;
264246bdb399SToby Isaac       PetscInt    matSize;
264321968bf8SToby Isaac       PetscInt    i;
264446bdb399SToby Isaac 
26459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&gDof));
26469566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&gcDof));
264746bdb399SToby Isaac       if ((gDof - gcDof) <= 0) {
264846bdb399SToby Isaac         continue;
264946bdb399SToby Isaac       }
26509566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine,p,&gOff));
265108401ef6SPierre Jolivet       PetscCheck(gOff >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset");
26521dca8a05SBarry Smith       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"I thought the row map would constrain the global dofs");
26539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec,p,&numColIndices));
26549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec,p,&pIndOff));
265546bdb399SToby Isaac       numColIndices -= 2 * numFields;
265608401ef6SPierre Jolivet       PetscCheck(numColIndices > 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from");
265746bdb399SToby Isaac       pInd = &leafIndices[pIndOff];
265821968bf8SToby Isaac       offsets[0]        = 0;
265921968bf8SToby Isaac       offsetsCopy[0]    = 0;
266021968bf8SToby Isaac       newOffsets[0]     = 0;
266121968bf8SToby Isaac       newOffsetsCopy[0] = 0;
266246bdb399SToby Isaac       if (numFields) {
266321968bf8SToby Isaac         PetscInt f;
266446bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
266546bdb399SToby Isaac           PetscInt rowDof;
266646bdb399SToby Isaac 
26679566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine,p,f,&rowDof));
266821968bf8SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
266921968bf8SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
267021968bf8SToby Isaac           newOffsets[f + 1]     = pInd[numColIndices + numFields + f];
267121968bf8SToby Isaac           numD[f] = 0;
267221968bf8SToby Isaac           numO[f] = 0;
267346bdb399SToby Isaac         }
26749566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices));
267546bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
267621968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
267721968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
267846bdb399SToby Isaac 
267946bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
268046bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
268146bdb399SToby Isaac 
268246bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
268321968bf8SToby Isaac               numD[f]++;
268446bdb399SToby Isaac             }
268546bdb399SToby Isaac             else if (gInd >= 0) { /* negative means non-entry */
268621968bf8SToby Isaac               numO[f]++;
268746bdb399SToby Isaac             }
268846bdb399SToby Isaac           }
268946bdb399SToby Isaac         }
269046bdb399SToby Isaac       }
269146bdb399SToby Isaac       else {
26929566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices));
269321968bf8SToby Isaac         numD[0] = 0;
269421968bf8SToby Isaac         numO[0] = 0;
269546bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
269646bdb399SToby Isaac           PetscInt gInd = pInd[i];
269746bdb399SToby Isaac 
269846bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
269921968bf8SToby Isaac             numD[0]++;
270046bdb399SToby Isaac           }
270146bdb399SToby Isaac           else if (gInd >= 0) { /* negative means non-entry */
270221968bf8SToby Isaac             numO[0]++;
270346bdb399SToby Isaac           }
270446bdb399SToby Isaac         }
270546bdb399SToby Isaac       }
27069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec,p,&matSize));
270746bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
270846bdb399SToby Isaac         PetscInt childId;
270946bdb399SToby Isaac 
271046bdb399SToby Isaac         childId = childIds[p-pStartF];
271121968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
271246bdb399SToby Isaac           if (numFields) {
2713b9a5774bSToby Isaac             PetscInt f;
2714b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
271521968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
271646bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
271721968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
271821968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
271946bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
27201dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2721b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
272246bdb399SToby Isaac                 }
272346bdb399SToby Isaac                 else if (gIndCoarse >= 0) { /* remote */
27241dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2725b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
272646bdb399SToby Isaac                 }
272746bdb399SToby Isaac                 else { /* constrained */
272808401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
272946bdb399SToby Isaac                 }
273046bdb399SToby Isaac               }
273146bdb399SToby Isaac             }
273246bdb399SToby Isaac           }
273346bdb399SToby Isaac           else {
2734b9a5774bSToby Isaac             PetscInt i;
2735b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
273646bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
273746bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
273846bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
27391dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2740b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
274146bdb399SToby Isaac               }
274246bdb399SToby Isaac               else if (gIndCoarse >= 0) { /* remote */
27431dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2744b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
274546bdb399SToby Isaac               }
274646bdb399SToby Isaac               else { /* constrained */
274708401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
274846bdb399SToby Isaac               }
274946bdb399SToby Isaac             }
275046bdb399SToby Isaac           }
275146bdb399SToby Isaac         }
275246bdb399SToby Isaac         else { /* interpolate from all */
275346bdb399SToby Isaac           if (numFields) {
2754b9a5774bSToby Isaac             PetscInt f;
2755b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
275621968bf8SToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
275746bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
275821968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
275946bdb399SToby Isaac                 if (gIndFine >= 0) {
27601dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2761b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2762b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
276346bdb399SToby Isaac                 }
276446bdb399SToby Isaac               }
276546bdb399SToby Isaac             }
276646bdb399SToby Isaac           }
276746bdb399SToby Isaac           else {
2768b9a5774bSToby Isaac             PetscInt i;
2769b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
277046bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
277146bdb399SToby Isaac               if (gIndFine >= 0) {
27721dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2773b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2774b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
277546bdb399SToby Isaac               }
277646bdb399SToby Isaac             }
277746bdb399SToby Isaac           }
277846bdb399SToby Isaac         }
277946bdb399SToby Isaac       }
278046bdb399SToby Isaac       else { /* interpolate from all */
278146bdb399SToby Isaac         if (numFields) {
2782b9a5774bSToby Isaac           PetscInt f;
2783b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
278421968bf8SToby Isaac             PetscInt numRows = offsets[f+1] - offsets[f], row;
278546bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
278621968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
278746bdb399SToby Isaac               if (gIndFine >= 0) {
27881dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2789b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2790b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
279146bdb399SToby Isaac               }
279246bdb399SToby Isaac             }
279346bdb399SToby Isaac           }
279446bdb399SToby Isaac         }
279546bdb399SToby Isaac         else { /* every dof get a full row */
2796b9a5774bSToby Isaac           PetscInt i;
2797b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
279846bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
279946bdb399SToby Isaac             if (gIndFine >= 0) {
28001dca8a05SBarry Smith               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs");
2801b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2802b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
280346bdb399SToby Isaac             }
280446bdb399SToby Isaac           }
280546bdb399SToby Isaac         }
280646bdb399SToby Isaac       }
280746bdb399SToby Isaac     }
28089566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL));
28099566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz,onnz));
281021968bf8SToby Isaac 
28119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine,&refTree));
28129566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
28139566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
28149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree,&refAnSec,NULL));
28159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
28169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec,&maxConDof));
28179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec,&maxColumns));
28189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof*maxColumns,&pointWork));
28190eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2820e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2821e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2822e44e4e7fSToby Isaac       PetscInt matSize;
2823e44e4e7fSToby Isaac       PetscInt childId;
2824e44e4e7fSToby Isaac 
28259566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&gDof));
28269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&gcDof));
2827e44e4e7fSToby Isaac       if ((gDof - gcDof) <= 0) {
2828e44e4e7fSToby Isaac         continue;
2829e44e4e7fSToby Isaac       }
2830e44e4e7fSToby Isaac       childId = childIds[p-pStartF];
28319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine,p,&gOff));
28329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec,p,&numColIndices));
28339566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec,p,&pIndOff));
2834e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2835e44e4e7fSToby Isaac       pInd = &leafIndices[pIndOff];
2836e44e4e7fSToby Isaac       offsets[0]        = 0;
2837e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2838e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2839e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2840e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2841e44e4e7fSToby Isaac       if (numFields) {
2842e44e4e7fSToby Isaac         PetscInt f;
2843e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2844e44e4e7fSToby Isaac           PetscInt rowDof;
2845e44e4e7fSToby Isaac 
28469566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine,p,f,&rowDof));
2847e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2848e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2849e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2850e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2851e44e4e7fSToby Isaac         }
28529566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,rowIndices));
2853e44e4e7fSToby Isaac       }
28541c58ffc4SToby Isaac       else {
28559566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,rowIndices));
28561c58ffc4SToby Isaac       }
28579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec,p,&matSize));
2858e44e4e7fSToby Isaac       if (!matSize) { /* incoming matrix is identity */
2859e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2860e44e4e7fSToby Isaac           if (numFields) {
2861e44e4e7fSToby Isaac             PetscInt f;
2862e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2863e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f], row;
2864e44e4e7fSToby Isaac               for (row = 0; row < numRows; row++) {
28659566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES));
286621968bf8SToby Isaac               }
286721968bf8SToby Isaac             }
2868e44e4e7fSToby Isaac           }
2869e44e4e7fSToby Isaac           else {
2870e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
2871e44e4e7fSToby Isaac             for (row = 0; row < numRows; row++) {
28729566063dSJacob Faibussowitsch               PetscCall(MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES));
2873e44e4e7fSToby Isaac             }
2874e44e4e7fSToby Isaac           }
2875e44e4e7fSToby Isaac         }
2876e44e4e7fSToby Isaac         else { /* interpolate from all */
2877e44e4e7fSToby Isaac           if (numFields) {
2878e44e4e7fSToby Isaac             PetscInt f;
2879e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2880e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1] - offsets[f];
2881e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
28829566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES));
2883e44e4e7fSToby Isaac             }
2884e44e4e7fSToby Isaac           }
2885e44e4e7fSToby Isaac           else {
28869566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES));
2887e44e4e7fSToby Isaac           }
2888e44e4e7fSToby Isaac         }
2889e44e4e7fSToby Isaac       }
2890e44e4e7fSToby Isaac       else { /* interpolate from all */
2891e44e4e7fSToby Isaac         PetscInt    pMatOff;
2892e44e4e7fSToby Isaac         PetscScalar *pMat;
2893e44e4e7fSToby Isaac 
28949566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec,p,&pMatOff));
2895e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2896e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2897e44e4e7fSToby Isaac           if (numFields) {
2898e44e4e7fSToby Isaac             PetscInt f, count;
2899e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2900e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2901e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2902e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2903e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2904e44e4e7fSToby Isaac 
29059566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES));
2906e44e4e7fSToby Isaac               count += numCols * numInRows;
2907e44e4e7fSToby Isaac             }
2908e44e4e7fSToby Isaac           }
2909e44e4e7fSToby Isaac           else {
29109566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES));
2911e44e4e7fSToby Isaac           }
2912e44e4e7fSToby Isaac         }
2913e44e4e7fSToby Isaac         else { /* multiply the incoming matrix by the child interpolation */
2914e44e4e7fSToby Isaac           if (numFields) {
2915e44e4e7fSToby Isaac             PetscInt f, count;
2916e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2917e44e4e7fSToby Isaac               PetscInt numRows = offsets[f+1]-offsets[f];
2918e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f+1]-newOffsets[f];
2919e44e4e7fSToby Isaac               PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f];
2920e44e4e7fSToby Isaac               PetscScalar *inMat = &pMat[count];
2921e44e4e7fSToby Isaac               PetscInt i, j, k;
292208401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2923e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2924e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2925e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2926e44e4e7fSToby Isaac                   for (k = 0; k < numInRows; k++) {
2927e44e4e7fSToby Isaac                     val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2928e44e4e7fSToby Isaac                   }
2929e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2930e44e4e7fSToby Isaac                 }
2931e44e4e7fSToby Isaac               }
29329566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES));
2933e44e4e7fSToby Isaac               count += numCols * numInRows;
2934e44e4e7fSToby Isaac             }
2935e44e4e7fSToby Isaac           }
2936267d4f3fSToby Isaac           else { /* every dof gets a full row */
2937e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2938e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2939e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2940e44e4e7fSToby Isaac             PetscInt i, j, k;
294108401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch");
2942e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2943e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2944e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2945e44e4e7fSToby Isaac                 for (k = 0; k < numInRows; k++) {
2946e44e4e7fSToby Isaac                   val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2947e44e4e7fSToby Isaac                 }
2948e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2949e44e4e7fSToby Isaac               }
2950e44e4e7fSToby Isaac             }
29519566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES));
2952e44e4e7fSToby Isaac           }
2953e44e4e7fSToby Isaac         }
2954e44e4e7fSToby Isaac       }
2955e44e4e7fSToby Isaac     }
29569566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
29579566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
29589566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2959e44e4e7fSToby Isaac   }
29609566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
29619566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
29629566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
29639566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
29649566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices,leafMatrices));
29659566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt****)&perms,*(PetscScalar****)&flips));
29669566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO));
29679566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
29686ecaa68aSToby Isaac   PetscFunctionReturn(0);
29696ecaa68aSToby Isaac }
2970154bca37SToby Isaac 
29718d2f55e7SToby Isaac /*
29728d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
29738d2f55e7SToby Isaac  *
29748d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
29758d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
29768d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
29778d2f55e7SToby Isaac  *       a_{i,j} = 0;
29788d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
29798d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
29808d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
29818d2f55e7SToby Isaac  */
29828d2f55e7SToby Isaac PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
29838d2f55e7SToby Isaac {
29848d2f55e7SToby Isaac   PetscDS        ds;
29858d2f55e7SToby Isaac   PetscSection   section, cSection;
29868d2f55e7SToby Isaac   DMLabel        canonical, depth;
29878d2f55e7SToby Isaac   Mat            cMat, mat;
29888d2f55e7SToby Isaac   PetscInt       *nnz;
29898d2f55e7SToby Isaac   PetscInt       f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
29908d2f55e7SToby Isaac   PetscInt       m, n;
29918d2f55e7SToby Isaac   PetscScalar    *pointScalar;
29928d2f55e7SToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
29938d2f55e7SToby Isaac 
29948d2f55e7SToby Isaac   PetscFunctionBegin;
29959566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree,&section));
29969566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
29979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ));
29989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim,&pointScalar,dim,&pointRef));
29999566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
30009566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
30019566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section,&numSecFields));
30029566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree,"canonical",&canonical));
30039566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree,"depth",&depth));
30049566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&cSection,&cMat,NULL));
30059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
30069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
30079566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat,&n,&m)); /* the injector has transpose sizes from the constraint matrix */
30088d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
30099566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m,&nnz));
30108d2f55e7SToby 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 */
30118d2f55e7SToby Isaac     const PetscInt *children;
30128d2f55e7SToby Isaac     PetscInt numChildren;
30138d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30148d2f55e7SToby Isaac 
30158d2f55e7SToby Isaac     if (canonical) {
30168d2f55e7SToby Isaac       PetscInt pCanonical;
30179566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical,p,&pCanonical));
30188d2f55e7SToby Isaac       if (p != pCanonical) continue;
30198d2f55e7SToby Isaac     }
30209566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree,p,&numChildren,&children));
30218d2f55e7SToby Isaac     if (!numChildren) continue;
30228d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30238d2f55e7SToby Isaac       PetscInt child = children[i];
30248d2f55e7SToby Isaac       PetscInt dof;
30258d2f55e7SToby Isaac 
30269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,child,&dof));
30278d2f55e7SToby Isaac       numChildDof += dof;
30288d2f55e7SToby Isaac     }
30299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section,p,&numSelfDof));
30308d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30318d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
30328d2f55e7SToby Isaac       PetscInt selfOff;
30338d2f55e7SToby Isaac 
30348d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
30358d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30368d2f55e7SToby Isaac           PetscInt child = children[i];
30378d2f55e7SToby Isaac           PetscInt dof;
30388d2f55e7SToby Isaac 
30399566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,child,f,&dof));
30408d2f55e7SToby Isaac           numChildDof += dof;
30418d2f55e7SToby Isaac         }
30429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section,p,f,&numSelfDof));
30439566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section,p,f,&selfOff));
30448d2f55e7SToby Isaac       }
30458d2f55e7SToby Isaac       else {
30469566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section,p,&selfOff));
30478d2f55e7SToby Isaac       }
30488d2f55e7SToby Isaac       for (i = 0; i < numSelfDof; i++) {
30498d2f55e7SToby Isaac         nnz[selfOff + i] = numChildDof;
30508d2f55e7SToby Isaac       }
30518d2f55e7SToby Isaac     }
30528d2f55e7SToby Isaac   }
30539566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat));
30549566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
30558d2f55e7SToby Isaac   /* Setp 2: compute entries */
30568d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
30578d2f55e7SToby Isaac     const PetscInt *children;
30588d2f55e7SToby Isaac     PetscInt numChildren;
30598d2f55e7SToby Isaac     PetscInt i, numChildDof, numSelfDof;
30608d2f55e7SToby Isaac 
30618d2f55e7SToby Isaac     /* same conditions about when entries occur */
30628d2f55e7SToby Isaac     if (canonical) {
30638d2f55e7SToby Isaac       PetscInt pCanonical;
30649566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical,p,&pCanonical));
30658d2f55e7SToby Isaac       if (p != pCanonical) continue;
30668d2f55e7SToby Isaac     }
30679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree,p,&numChildren,&children));
30688d2f55e7SToby Isaac     if (!numChildren) continue;
30698d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
30708d2f55e7SToby Isaac       PetscInt child = children[i];
30718d2f55e7SToby Isaac       PetscInt dof;
30728d2f55e7SToby Isaac 
30739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section,child,&dof));
30748d2f55e7SToby Isaac       numChildDof += dof;
30758d2f55e7SToby Isaac     }
30769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section,p,&numSelfDof));
30778d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
30788d2f55e7SToby Isaac 
30798d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
308059fc6756SToby Isaac       PetscInt       pI = -1, cI = -1;
308152a3aeb4SToby Isaac       PetscInt       selfOff, Nc, parentCell;
30828d2f55e7SToby Isaac       PetscInt       cellShapeOff;
30838d2f55e7SToby Isaac       PetscObject    disc;
30848d2f55e7SToby Isaac       PetscDualSpace dsp;
30858d2f55e7SToby Isaac       PetscClassId   classId;
30868d2f55e7SToby Isaac       PetscScalar    *pointMat;
30873b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
30888d2f55e7SToby Isaac       PetscInt       pO = PETSC_MIN_INT;
30898d2f55e7SToby Isaac       const PetscInt *depthNumDof;
30908d2f55e7SToby Isaac 
30918d2f55e7SToby Isaac       if (numSecFields) {
30928d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
30938d2f55e7SToby Isaac           PetscInt child = children[i];
30948d2f55e7SToby Isaac           PetscInt dof;
30958d2f55e7SToby Isaac 
30969566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section,child,f,&dof));
30978d2f55e7SToby Isaac           numChildDof += dof;
30988d2f55e7SToby Isaac         }
30999566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section,p,f,&numSelfDof));
31009566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section,p,f,&selfOff));
31018d2f55e7SToby Isaac       }
31028d2f55e7SToby Isaac       else {
31039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section,p,&selfOff));
31048d2f55e7SToby Isaac       }
31058d2f55e7SToby Isaac 
31063b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
31078d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
31088d2f55e7SToby Isaac         parentCell = p;
31098d2f55e7SToby Isaac       }
31108d2f55e7SToby Isaac       else {
31118d2f55e7SToby Isaac         PetscInt *star = NULL;
31128d2f55e7SToby Isaac         PetscInt numStar;
31138d2f55e7SToby Isaac 
31148d2f55e7SToby Isaac         parentCell = -1;
31159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star));
31168d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
31178d2f55e7SToby Isaac           PetscInt c = star[2 * i];
31188d2f55e7SToby Isaac 
31198d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
31208d2f55e7SToby Isaac             parentCell = c;
31218d2f55e7SToby Isaac             break;
31228d2f55e7SToby Isaac           }
31238d2f55e7SToby Isaac         }
31249566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star));
31258d2f55e7SToby Isaac       }
3126a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
31279566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds,f,&disc));
31289566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc,&classId));
3129c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
31309566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp));
3131c5356c36SToby Isaac       }
3132c5356c36SToby Isaac       else if (classId == PETSCFV_CLASSID) {
31339566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc,&dsp));
3134c5356c36SToby Isaac       }
3135c5356c36SToby Isaac       else {
31369b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");
3137c5356c36SToby Isaac       }
31389566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp,&depthNumDof));
31399566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp,&Nc));
31408d2f55e7SToby Isaac       {
31418d2f55e7SToby Isaac         PetscInt *closure = NULL;
31428d2f55e7SToby Isaac         PetscInt numClosure;
31438d2f55e7SToby Isaac 
31449566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure));
314559fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
31468d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
31478d2f55e7SToby Isaac 
31488d2f55e7SToby Isaac           pO = closure[2 * i + 1];
314959fc6756SToby Isaac           if (point == p) {
315059fc6756SToby Isaac             pI = i;
315159fc6756SToby Isaac             break;
315259fc6756SToby Isaac           }
31539566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth,point,&pointDepth));
31548d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
31558d2f55e7SToby Isaac         }
31569566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure));
31578d2f55e7SToby Isaac       }
31588d2f55e7SToby Isaac 
31599566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat));
31609566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows));
316152a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
316252a3aeb4SToby Isaac       for (i = 0; i < numSelfDof; i++) {
316352a3aeb4SToby Isaac         matRows[i] = selfOff + i;
31643b1c2a6aSToby Isaac       }
316552a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
31663b1c2a6aSToby Isaac       {
31673b1c2a6aSToby Isaac         PetscInt colOff = 0;
31683b1c2a6aSToby Isaac 
31693b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
31703b1c2a6aSToby Isaac           PetscInt child = children[i];
31713b1c2a6aSToby Isaac           PetscInt dof, off, j;
31723b1c2a6aSToby Isaac 
31733b1c2a6aSToby Isaac           if (numSecFields) {
31749566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection,child,f,&dof));
31759566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection,child,f,&off));
31763b1c2a6aSToby Isaac           }
31773b1c2a6aSToby Isaac           else {
31789566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection,child,&dof));
31799566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection,child,&off));
31803b1c2a6aSToby Isaac           }
31813b1c2a6aSToby Isaac 
318252a3aeb4SToby Isaac           for (j = 0; j < dof; j++) {
318352a3aeb4SToby Isaac             matCols[colOff++] = off + j;
31843b1c2a6aSToby Isaac           }
31853b1c2a6aSToby Isaac         }
31863b1c2a6aSToby Isaac       }
31878d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
31888d2f55e7SToby Isaac         PetscFE        fe = (PetscFE) disc;
31898d2f55e7SToby Isaac         PetscInt       fSize;
319059fc6756SToby Isaac         const PetscInt ***perms;
319159fc6756SToby Isaac         const PetscScalar ***flips;
319259fc6756SToby Isaac         const PetscInt *pperms;
319359fc6756SToby Isaac 
31949566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe,&dsp));
31959566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp,&fSize));
31969566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
319759fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
319852a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
31998d2f55e7SToby Isaac           PetscQuadrature q;
320052a3aeb4SToby Isaac           PetscInt        dim, thisNc, numPoints, j, k;
32018d2f55e7SToby Isaac           const PetscReal *points;
32028d2f55e7SToby Isaac           const PetscReal *weights;
32038d2f55e7SToby Isaac           PetscInt        *closure = NULL;
32048d2f55e7SToby Isaac           PetscInt        numClosure;
320559fc6756SToby Isaac           PetscInt        iCell = pperms ? pperms[i] : i;
320659fc6756SToby Isaac           PetscInt        parentCellShapeDof = cellShapeOff + iCell;
3207ef0bb6c7SMatthew G. Knepley           PetscTabulation Tparent;
32088d2f55e7SToby Isaac 
32099566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q));
32109566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q,&dim,&thisNc,&numPoints,&points,&weights));
321163a3b9bcSJacob Faibussowitsch           PetscCheck(thisNc == Nc,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT,thisNc,Nc);
32129566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe,1,numPoints,points,0,&Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
32133b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
32148d2f55e7SToby Isaac             PetscInt          childCell = -1;
321552a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3216c330f8ffSToby Isaac             const PetscReal   xi0[3] = {-1.,-1.,-1.};
32178d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
32188d2f55e7SToby Isaac             const PetscScalar *point;
3219ef0bb6c7SMatthew G. Knepley             PetscTabulation Tchild;
32208d2f55e7SToby Isaac             PetscInt          childCellShapeOff, pointMatOff;
32218d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
32228d2f55e7SToby Isaac             PetscInt          d;
32238d2f55e7SToby Isaac 
32248d2f55e7SToby Isaac             for (d = 0; d < dim; d++) {
32258d2f55e7SToby Isaac               pointScalar[d] = points[dim * j + d];
32268d2f55e7SToby Isaac             }
32278d2f55e7SToby Isaac             point = pointScalar;
32288d2f55e7SToby Isaac #else
32298d2f55e7SToby Isaac             point = pointReal;
32308d2f55e7SToby Isaac #endif
32318d2f55e7SToby Isaac 
3232ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
32333b1c2a6aSToby Isaac 
32343b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
32358d2f55e7SToby Isaac               PetscInt child = children[k];
32368d2f55e7SToby Isaac               PetscInt *star = NULL;
32378d2f55e7SToby Isaac               PetscInt numStar, s;
32388d2f55e7SToby Isaac 
32399566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star));
32408d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
32418d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
32428d2f55e7SToby Isaac 
32438d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
32449566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell));
32458d2f55e7SToby Isaac                 if (childCell >= 0) break;
32468d2f55e7SToby Isaac               }
32479566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star));
32488d2f55e7SToby Isaac               if (childCell >= 0) break;
32498d2f55e7SToby Isaac             }
325008401ef6SPierre Jolivet             PetscCheck(childCell >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");
32519566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
32529566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3253c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3254c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
32558d2f55e7SToby Isaac 
32569566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe,1,1,pointRef,0,&Tchild));
32579566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure));
32583b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3259c5356c36SToby Isaac               PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
32608d2f55e7SToby Isaac               PetscInt l;
326159fc6756SToby Isaac               const PetscInt *cperms;
32628d2f55e7SToby Isaac 
32639566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth,child,&childDepth));
32648d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
326559fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
32668d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
32678d2f55e7SToby Isaac                 PetscInt pointDepth;
32688d2f55e7SToby Isaac 
32698d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
327059fc6756SToby Isaac                 if (point == child) {
327159fc6756SToby Isaac                   cI = l;
327259fc6756SToby Isaac                   break;
327359fc6756SToby Isaac                 }
32749566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth,point,&pointDepth));
32758d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
32768d2f55e7SToby Isaac               }
32778d2f55e7SToby Isaac               if (l == numClosure) {
32788d2f55e7SToby Isaac                 pointMatOff += childDof;
32798d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
32808d2f55e7SToby Isaac               }
328159fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
32828d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
328359fc6756SToby Isaac                 PetscInt    lCell = cperms ? cperms[l] : l;
328459fc6756SToby Isaac                 PetscInt    childCellDof = childCellShapeOff + lCell;
328552a3aeb4SToby Isaac                 PetscReal   *childValAtPoint;
328652a3aeb4SToby Isaac                 PetscReal   val = 0.;
32878d2f55e7SToby Isaac 
3288ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
328952a3aeb4SToby Isaac                 for (m = 0; m < Nc; m++) {
329052a3aeb4SToby Isaac                   val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
329152a3aeb4SToby Isaac                 }
329252a3aeb4SToby Isaac 
329352a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
32948d2f55e7SToby Isaac               }
32958d2f55e7SToby Isaac               pointMatOff += childDof;
32968d2f55e7SToby Isaac             }
32979566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure));
32989566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
32998d2f55e7SToby Isaac           }
33009566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
33018d2f55e7SToby Isaac         }
33028d2f55e7SToby Isaac       }
3303c5356c36SToby Isaac       else { /* just the volume-weighted averages of the children */
33043b1c2a6aSToby Isaac         PetscReal parentVol;
3305bfaa5bdcSToby Isaac         PetscInt  childCell;
33063b1c2a6aSToby Isaac 
33079566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3308bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
330952a3aeb4SToby Isaac           PetscInt  child = children[i], j;
33103b1c2a6aSToby Isaac           PetscReal childVol;
33113b1c2a6aSToby Isaac 
33123b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
33139566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
331452a3aeb4SToby Isaac           for (j = 0; j < Nc; j++) {
3315bfaa5bdcSToby Isaac             pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
331652a3aeb4SToby Isaac           }
3317bfaa5bdcSToby Isaac           childCell++;
33183b1c2a6aSToby Isaac         }
33198d2f55e7SToby Isaac       }
33203b1c2a6aSToby Isaac       /* Insert pointMat into mat */
33219566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat,numSelfDof,matRows,numChildDof,matCols,pointMat,INSERT_VALUES));
33229566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT,&matRows));
33239566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR,&pointMat));
33248d2f55e7SToby Isaac     }
33258d2f55e7SToby Isaac   }
33269566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ));
33279566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar,pointRef));
33289566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
33299566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
33308d2f55e7SToby Isaac   *inj = mat;
33318d2f55e7SToby Isaac   PetscFunctionReturn(0);
33328d2f55e7SToby Isaac }
33338d2f55e7SToby Isaac 
3334f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3335f30e825dSToby Isaac {
3336f30e825dSToby Isaac   PetscDS        ds;
3337f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3338f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3339f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3340f30e825dSToby Isaac 
3341f30e825dSToby Isaac   PetscFunctionBegin;
33429566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
33439566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
33449566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
33459566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree,&refSection));
33469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
33479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats));
33489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec,&maxDof));
33499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof,&rows));
33509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof*maxDof,&cols));
3351f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3352f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3353f30e825dSToby Isaac 
33549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree,p,&parent,NULL));
33559566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec,p,&pDof));
33569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection,parent,&parentDof));
3357f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3358f30e825dSToby Isaac 
33599566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]));
3360f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
336152a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3362f30e825dSToby Isaac 
3363f30e825dSToby Isaac       if (numFields > 1) {
33649566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
33659566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec,p,f,&cOff));
3366f30e825dSToby Isaac       }
3367f30e825dSToby Isaac       else {
33689566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec,p,&cDof));
33699566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec,p,&cOff));
3370f30e825dSToby Isaac       }
3371f30e825dSToby Isaac 
3372f30e825dSToby Isaac       for (r = 0; r < cDof; r++) {
3373f30e825dSToby Isaac         rows[r] = cOff + r;
3374f30e825dSToby Isaac       }
3375f30e825dSToby Isaac       numCols = 0;
3376f30e825dSToby Isaac       {
3377f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3378f30e825dSToby Isaac 
3379f30e825dSToby Isaac         if (numFields > 1) {
33809566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection,parent,f,&aDof));
33819566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection,parent,f,&aOff));
3382f30e825dSToby Isaac         }
3383f30e825dSToby Isaac         else {
33849566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection,parent,&aDof));
33859566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection,parent,&aOff));
3386f30e825dSToby Isaac         }
3387f30e825dSToby Isaac 
3388f30e825dSToby Isaac         for (j = 0; j < aDof; j++) {
3389f30e825dSToby Isaac           cols[numCols++] = aOff + j;
3390f30e825dSToby Isaac         }
3391f30e825dSToby Isaac       }
33929566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]));
3393f30e825dSToby Isaac       /* transpose of constraint matrix */
33949566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]));
3395f30e825dSToby Isaac     }
3396f30e825dSToby Isaac   }
3397f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
33989566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
33999566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
3400f30e825dSToby Isaac   PetscFunctionReturn(0);
3401f30e825dSToby Isaac }
3402f30e825dSToby Isaac 
3403f30e825dSToby Isaac static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3404f30e825dSToby Isaac {
3405f30e825dSToby Isaac   PetscDS        ds;
3406f30e825dSToby Isaac   PetscScalar    ***refPointFieldMats;
3407f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3408c6154584SToby Isaac   PetscSection   refConSec, refSection;
3409f30e825dSToby Isaac 
3410f30e825dSToby Isaac   PetscFunctionBegin;
3411f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3412f30e825dSToby Isaac   *childrenMats = NULL;
34139566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree,&ds));
34149566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree,&refSection));
34159566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds,&numFields));
34169566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
34179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
3418f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3419f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3420f30e825dSToby Isaac 
34219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree,p,&parent,NULL));
34229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec,p,&pDof));
34239566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection,parent,&parentDof));
3424f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3425f30e825dSToby Isaac 
3426f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3427f30e825dSToby Isaac       PetscInt cDof;
3428f30e825dSToby Isaac 
3429f30e825dSToby Isaac       if (numFields > 1) {
34309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec,p,f,&cDof));
3431f30e825dSToby Isaac       }
3432f30e825dSToby Isaac       else {
34339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec,p,&cDof));
3434f30e825dSToby Isaac       }
3435f30e825dSToby Isaac 
34369566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3437f30e825dSToby Isaac     }
34389566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3439f30e825dSToby Isaac   }
34409566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
3441f30e825dSToby Isaac   PetscFunctionReturn(0);
3442f30e825dSToby Isaac }
3443f30e825dSToby Isaac 
3444ebf164c7SToby Isaac static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef)
3445154bca37SToby Isaac {
3446ebf164c7SToby Isaac   Mat            cMatRef;
34476148253fSToby Isaac   PetscObject    injRefObj;
34488d2f55e7SToby Isaac 
3449154bca37SToby Isaac   PetscFunctionBegin;
34509566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,NULL,&cMatRef,NULL));
34519566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj));
3452ebf164c7SToby Isaac   *injRef = (Mat) injRefObj;
3453ebf164c7SToby Isaac   if (!*injRef) {
34549566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree,injRef));
34559566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef));
3456ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
34579566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3458ebf164c7SToby Isaac   }
3459ebf164c7SToby Isaac   PetscFunctionReturn(0);
34606148253fSToby Isaac }
3461f30e825dSToby Isaac 
3462c921d74cSToby 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)
3463ebf164c7SToby Isaac {
3464c921d74cSToby Isaac   PetscInt       pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3465ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3466ebf164c7SToby Isaac   PetscSection   localCoarse, localFine, leafIndicesSec;
3467c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3468c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3469c921d74cSToby Isaac   const PetscInt *rootDegrees;
3470c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3471ebf164c7SToby Isaac   PetscSF        coarseToFineEmbedded;
3472ebf164c7SToby Isaac 
3473ebf164c7SToby Isaac   PetscFunctionBegin;
34749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
34759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
34769566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
34779566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
34789566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec));
34799566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec,pStartF, pEndF));
34809566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine,&maxDof));
34818d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
34827e96bdafSToby Isaac     PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
34837e96bdafSToby Isaac     const PetscInt *leaves;
34848d2f55e7SToby Isaac 
34859566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL));
34867e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
34877e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
34889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
34899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
34908d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
34918d2f55e7SToby Isaac         numPointsWithDofs++;
3492f30e825dSToby Isaac 
34939566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine,p,&dof));
34949566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec,p,dof + 1));
34958d2f55e7SToby Isaac       }
34968d2f55e7SToby Isaac     }
34979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
34989566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
34999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec,&numIndices));
35009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds));
35019566063dSJacob Faibussowitsch     if (gatheredValues)  PetscCall(PetscMalloc1(numIndices,&leafVals));
35027e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
35037e96bdafSToby Isaac       p    = leaves ? leaves[l] : l;
35049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
35059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
35068d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3507f30e825dSToby Isaac         PetscInt    off, gOff;
3508f30e825dSToby Isaac         PetscInt    *pInd;
3509c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3510f30e825dSToby Isaac 
35117e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3512f30e825dSToby Isaac 
35139566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec,p,&off));
3514f30e825dSToby Isaac 
3515c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3516c921d74cSToby Isaac         if (gatheredValues) {
3517c921d74cSToby Isaac           PetscInt i;
3518c921d74cSToby Isaac 
3519c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3520c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3521c921d74cSToby Isaac         }
35229566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine,p,&gOff));
3523f30e825dSToby Isaac 
3524f30e825dSToby Isaac         offsets[0] = 0;
3525f30e825dSToby Isaac         if (numFields) {
3526f30e825dSToby Isaac           PetscInt f;
3527f30e825dSToby Isaac 
3528f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3529f30e825dSToby Isaac             PetscInt fDof;
35309566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine,p,f,&fDof));
3531f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3532f30e825dSToby Isaac           }
35339566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL,-1, NULL,pInd));
3534367003a6SStefano Zampini         } else {
35359566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,NULL, NULL,pInd));
3536f30e825dSToby Isaac         }
35379566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec,dof,pInd,pVal));
35388d2f55e7SToby Isaac       }
35398d2f55e7SToby Isaac     }
35409566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
35419566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
35428d2f55e7SToby Isaac   }
3543f30e825dSToby Isaac 
35449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
35459566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
35469566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
3547f30e825dSToby Isaac 
35486148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
35496148253fSToby Isaac     MPI_Datatype threeInt;
35506148253fSToby Isaac     PetscMPIInt  rank;
35516148253fSToby Isaac     PetscInt     (*parentNodeAndIdCoarse)[3];
35526148253fSToby Isaac     PetscInt     (*parentNodeAndIdFine)[3];
35536148253fSToby Isaac     PetscInt     p, nleaves, nleavesToParents;
35546148253fSToby Isaac     PetscSF      pointSF, sfToParents;
35556148253fSToby Isaac     const PetscInt *ilocal;
35566148253fSToby Isaac     const PetscSFNode *iremote;
35576148253fSToby Isaac     PetscSFNode  *iremoteToParents;
35586148253fSToby Isaac     PetscInt     *ilocalToParents;
35596148253fSToby Isaac 
35609566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank));
35619566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3,MPIU_INT,&threeInt));
35629566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
35639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine));
35649566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse,&pointSF));
35659566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote));
35666148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
35676148253fSToby Isaac       PetscInt parent, childId;
35689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse,p,&parent,&childId));
35696148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
35706148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
35716148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
35726148253fSToby Isaac       if (nleaves > 0) {
35736148253fSToby Isaac         PetscInt leaf = -1;
35746148253fSToby Isaac 
35756148253fSToby Isaac         if (ilocal) {
35769566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent,nleaves,ilocal,&leaf));
35776148253fSToby Isaac         }
35786148253fSToby Isaac         else {
35796148253fSToby Isaac           leaf = p - pStartC;
35806148253fSToby Isaac         }
35816148253fSToby Isaac         if (leaf >= 0) {
35826148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
35836148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
35846148253fSToby Isaac         }
35856148253fSToby Isaac       }
35866148253fSToby Isaac     }
35876148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
35886148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
35896148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
35906148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
35916148253fSToby Isaac     }
35929566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine,MPI_REPLACE));
35939566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine,MPI_REPLACE));
35946148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3595f30e825dSToby Isaac       PetscInt dof;
3596f30e825dSToby Isaac 
35979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec,p,&dof));
3598f30e825dSToby Isaac       if (dof) {
3599f30e825dSToby Isaac         PetscInt off;
3600f30e825dSToby Isaac 
36019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec,p,&off));
3602c921d74cSToby Isaac         if (gatheredIndices) {
3603c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3604c921d74cSToby Isaac         } else if (gatheredValues) {
3605c921d74cSToby Isaac           leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]);
3606c921d74cSToby Isaac         }
3607f30e825dSToby Isaac       }
36086148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36096148253fSToby Isaac         nleavesToParents++;
36106148253fSToby Isaac       }
36116148253fSToby Isaac     }
36129566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents,&ilocalToParents));
36139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents,&iremoteToParents));
36146148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
36156148253fSToby Isaac       if (parentNodeAndIdFine[p-pStartF][0] >= 0) {
36166148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
36176148253fSToby Isaac         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p-pStartF][0];
36186148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1];
36196148253fSToby Isaac         nleavesToParents++;
36206148253fSToby Isaac       }
36216148253fSToby Isaac     }
36229566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents));
36239566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER));
36249566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
36256148253fSToby Isaac 
36266148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
36276148253fSToby Isaac 
36289566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine));
36299566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
36306148253fSToby Isaac   }
3631f30e825dSToby Isaac 
36326148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
36336148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
36346148253fSToby Isaac     PetscSF  sfDofsOnly;
36356148253fSToby Isaac 
36366148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
36379566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
36389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
36396148253fSToby Isaac       if ((dof - cdof) > 0) {
36406148253fSToby Isaac         numPointsWithDofs++;
36416148253fSToby Isaac       }
36426148253fSToby Isaac     }
36439566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
36446148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
36459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
36469566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
36476148253fSToby Isaac       if ((dof - cdof) > 0) {
3648e03d9830SToby Isaac         pointsWithDofs[offset++] = p - pStartC;
36496148253fSToby Isaac       }
36506148253fSToby Isaac     }
36519566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
36529566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
36539566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
36546148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
36556148253fSToby Isaac   }
3656f30e825dSToby Isaac 
36576148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
36589566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees));
36599566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees));
36609566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec));
36619566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec,pStartC,pEndC));
36628d2f55e7SToby Isaac   for (p = pStartC; p < pEndC; p++) {
36639566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]));
36648d2f55e7SToby Isaac   }
36659566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
36669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec,&numMulti));
36679566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec));
3668f30e825dSToby Isaac   { /* distribute the leaf section */
3669f30e825dSToby Isaac     PetscSF multi, multiInv, indicesSF;
3670f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
36718d2f55e7SToby Isaac 
36729566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded,&multi));
36739566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi,&multiInv));
36749566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec));
36759566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF));
36769566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
36779566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
36789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices));
3679c921d74cSToby Isaac     if (gatheredIndices) {
36809566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices,&rootInds));
36819566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds,MPI_REPLACE));
36829566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds,MPI_REPLACE));
3683c921d74cSToby Isaac     }
3684c921d74cSToby Isaac     if (gatheredValues) {
36859566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices,&rootVals));
36869566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals,MPI_REPLACE));
36879566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals,MPI_REPLACE));
3688c921d74cSToby Isaac     }
36899566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
36908d2f55e7SToby Isaac   }
36919566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
36929566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
36939566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
36949566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3695c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3696c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3697c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3698c921d74cSToby Isaac   if (gatheredValues)  *gatheredValues  = rootVals;
3699ebf164c7SToby Isaac   PetscFunctionReturn(0);
3700ebf164c7SToby Isaac }
3701ebf164c7SToby Isaac 
3702ebf164c7SToby Isaac PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3703ebf164c7SToby Isaac {
3704ebf164c7SToby Isaac   DM             refTree;
3705c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3706ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3707ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3708ebf164c7SToby Isaac   PetscSection   cSecRef;
3709277f51e8SBarry Smith   PetscInt       *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3710ebf164c7SToby Isaac   Mat            injRef;
3711c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3712ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3713ebf164c7SToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
3714ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3715ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3716ebf164c7SToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3717ebf164c7SToby Isaac 
3718ebf164c7SToby Isaac   PetscFunctionBegin;
3719ebf164c7SToby Isaac 
3720ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
37219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse,&refTree));
37229566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&cSecRef,NULL,NULL));
37239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd));
37249566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree,&injRef));
3725ebf164c7SToby Isaac 
37269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
37279566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
37289566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
37299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine,&numFields));
37309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
37319566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
37329566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
37339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse,&maxDof));
3734ebf164c7SToby Isaac   {
3735ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
37369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets));
3737ebf164c7SToby Isaac   }
3738ebf164c7SToby Isaac 
37399566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL));
37408d2f55e7SToby Isaac 
37419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof,&parentIndices));
3742f30e825dSToby Isaac 
3743f30e825dSToby Isaac   /* count indices */
37449566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat,&rowMap,&colMap));
37459566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
37469566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
37479566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap,&rowStart,&rowEnd));
37489566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap,&colStart,&colEnd));
37499566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO));
3750f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3751f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
37528d2f55e7SToby Isaac 
37539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
37549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
3755f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
37569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse,p,&gOff));
37578d2f55e7SToby Isaac 
37588d2f55e7SToby Isaac     rowOffsets[0] = 0;
3759f30e825dSToby Isaac     offsetsCopy[0] = 0;
37608d2f55e7SToby Isaac     if (numFields) {
37618d2f55e7SToby Isaac       PetscInt f;
37628d2f55e7SToby Isaac 
3763f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3764f30e825dSToby Isaac         PetscInt fDof;
37659566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
3766f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
37678d2f55e7SToby Isaac       }
37689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices));
3769367003a6SStefano Zampini     } else {
37709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices));
3771f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
37728d2f55e7SToby Isaac     }
3773f30e825dSToby Isaac 
37749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec,p,&numLeaves));
37759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec,p,&leafStart));
3776f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3777f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3778f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3779f30e825dSToby Isaac       const PetscInt *childIndices;
3780f30e825dSToby Isaac 
37819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec,l,&numIndices));
37829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec,l,&offset));
3783f30e825dSToby Isaac       childId = rootIndices[offset++];
3784f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3785f30e825dSToby Isaac       numIndices--;
3786f30e825dSToby Isaac 
3787f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3788f30e825dSToby Isaac         PetscInt i;
3789f30e825dSToby Isaac 
3790f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3791f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3792f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3793f30e825dSToby Isaac           if (rowIndex < 0) continue;
379408401ef6SPierre Jolivet           PetscCheck(colIndex >= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse");
3795a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3796f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
3797f30e825dSToby Isaac           }
3798f30e825dSToby Isaac           else {
3799f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3800f30e825dSToby Isaac           }
3801f30e825dSToby Isaac         }
3802f30e825dSToby Isaac       }
3803f30e825dSToby Isaac       else {
3804f30e825dSToby Isaac         PetscInt parentId, f, lim;
3805f30e825dSToby Isaac 
38069566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree,childId,&parentId,NULL));
3807f30e825dSToby Isaac 
3808f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3809f30e825dSToby Isaac         offsets[0] = 0;
38108d2f55e7SToby Isaac         if (numFields) {
38118d2f55e7SToby Isaac           PetscInt f;
3812f30e825dSToby Isaac 
38138d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3814f30e825dSToby Isaac             PetscInt fDof;
38159566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef,childId,f,&fDof));
3816f30e825dSToby Isaac 
3817f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
38188d2f55e7SToby Isaac           }
38198d2f55e7SToby Isaac         }
38208d2f55e7SToby Isaac         else {
3821f30e825dSToby Isaac           PetscInt cDof;
3822f30e825dSToby Isaac 
38239566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef,childId,&cDof));
3824f30e825dSToby Isaac           offsets[1] = cDof;
3825f30e825dSToby Isaac         }
3826f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3827f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3828f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3829f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3830f30e825dSToby Isaac 
3831f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3832f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3833f30e825dSToby Isaac 
3834f30e825dSToby Isaac             if (colIndex < 0) continue;
3835f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3836f30e825dSToby Isaac               numD++;
3837f30e825dSToby Isaac             }
3838f30e825dSToby Isaac             else {
3839f30e825dSToby Isaac               numO++;
3840f30e825dSToby Isaac             }
3841f30e825dSToby Isaac           }
3842f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3843f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3844f30e825dSToby Isaac 
3845f30e825dSToby Isaac             if (rowIndex < 0) continue;
3846f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3847f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
38488d2f55e7SToby Isaac           }
38498d2f55e7SToby Isaac         }
38508d2f55e7SToby Isaac       }
3851f30e825dSToby Isaac     }
3852f30e825dSToby Isaac   }
3853f30e825dSToby Isaac   /* preallocate */
38549566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL));
38559566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD,nnzO));
3856f30e825dSToby Isaac   /* insert values */
38579566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats));
3858f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3859f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3860f30e825dSToby Isaac 
38619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
38629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
3863f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
38649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse,p,&gOff));
3865f30e825dSToby Isaac 
3866f30e825dSToby Isaac     rowOffsets[0] = 0;
3867f30e825dSToby Isaac     offsetsCopy[0] = 0;
38688d2f55e7SToby Isaac     if (numFields) {
38698d2f55e7SToby Isaac       PetscInt f;
3870f30e825dSToby Isaac 
38718d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3872f30e825dSToby Isaac         PetscInt fDof;
38739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
3874f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3875f30e825dSToby Isaac       }
38769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1, NULL,parentIndices));
3877367003a6SStefano Zampini     } else {
38789566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL, NULL,parentIndices));
3879f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3880f30e825dSToby Isaac     }
3881f30e825dSToby Isaac 
38829566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec,p,&numLeaves));
38839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec,p,&leafStart));
3884f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3885f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3886f30e825dSToby Isaac       PetscInt numIndices, childId, offset;
3887f30e825dSToby Isaac       const PetscInt *childIndices;
3888f30e825dSToby Isaac 
38899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec,l,&numIndices));
38909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec,l,&offset));
3891f30e825dSToby Isaac       childId = rootIndices[offset++];
3892f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3893f30e825dSToby Isaac       numIndices--;
3894f30e825dSToby Isaac 
3895f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3896f30e825dSToby Isaac         PetscInt i;
3897f30e825dSToby Isaac 
3898f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
38999566063dSJacob Faibussowitsch           PetscCall(MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES));
39008d2f55e7SToby Isaac         }
39018d2f55e7SToby Isaac       }
39028d2f55e7SToby Isaac       else {
3903f30e825dSToby Isaac         PetscInt parentId, f, lim;
39048d2f55e7SToby Isaac 
39059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree,childId,&parentId,NULL));
3906f30e825dSToby Isaac 
3907f30e825dSToby Isaac         lim = PetscMax(1,numFields);
3908f30e825dSToby Isaac         offsets[0] = 0;
39098d2f55e7SToby Isaac         if (numFields) {
3910f30e825dSToby Isaac           PetscInt f;
39118d2f55e7SToby Isaac 
3912f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3913f30e825dSToby Isaac             PetscInt fDof;
39149566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef,childId,f,&fDof));
3915f30e825dSToby Isaac 
3916f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
39178d2f55e7SToby Isaac           }
39188d2f55e7SToby Isaac         }
39198d2f55e7SToby Isaac         else {
3920f30e825dSToby Isaac           PetscInt cDof;
3921f30e825dSToby Isaac 
39229566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef,childId,&cDof));
3923f30e825dSToby Isaac           offsets[1] = cDof;
39248d2f55e7SToby Isaac         }
3925f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3926f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3927f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3928f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3929f30e825dSToby Isaac 
39309566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES));
39318d2f55e7SToby Isaac         }
39328d2f55e7SToby Isaac       }
39338d2f55e7SToby Isaac     }
39348d2f55e7SToby Isaac   }
39359566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
39369566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
39379566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
39389566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats));
39399566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
39409566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets,offsetsCopy,rowOffsets));
3941f30e825dSToby Isaac 
39429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
39439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
3944154bca37SToby Isaac   PetscFunctionReturn(0);
3945154bca37SToby Isaac }
394638fc2455SToby Isaac 
39470eb7e1eaSToby Isaac static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3948ebf164c7SToby Isaac {
394962095d54SToby Isaac   PetscSF           coarseToFineEmbedded;
395062095d54SToby Isaac   PetscSection      globalCoarse, globalFine;
395162095d54SToby Isaac   PetscSection      localCoarse, localFine;
395262095d54SToby Isaac   PetscSection      aSec, cSec;
395362095d54SToby Isaac   PetscSection      rootValuesSec;
395462095d54SToby Isaac   PetscSection      leafValuesSec;
395562095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
395662095d54SToby Isaac   IS                aIS;
395762095d54SToby Isaac   const PetscInt    *anchors;
395862095d54SToby Isaac   Mat               cMat;
395962095d54SToby Isaac   PetscInt          numFields;
3960412e9a14SMatthew G. Knepley   PetscInt          pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
396162095d54SToby Isaac   PetscInt          aStart, aEnd, cStart, cEnd;
396262095d54SToby Isaac   PetscInt          *maxChildIds;
396362095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
39640eb7e1eaSToby Isaac   PetscFV           fv = NULL;
39650eb7e1eaSToby Isaac   PetscInt          dim, numFVcomps = -1, fvField = -1;
39660eb7e1eaSToby Isaac   DM                cellDM = NULL, gradDM = NULL;
39670eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
39680eb7e1eaSToby Isaac   const PetscScalar *gradArray = NULL;
396962095d54SToby Isaac 
3970ebf164c7SToby Isaac   PetscFunctionBegin;
39719566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE));
39729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
39739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse,0,&cellStart,&cellEnd));
39749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
39759566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
39769566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse,&dim));
397762095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3978e4a60869SToby Isaac     PetscInt       nleaves, l;
3979e4a60869SToby Isaac     const PetscInt *leaves;
398062095d54SToby Isaac     PetscInt       dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
398162095d54SToby Isaac 
39829566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL));
3983e4a60869SToby Isaac 
3984e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3985e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3986e4a60869SToby Isaac 
39879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
39889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
398962095d54SToby Isaac       if ((dof - cdof) > 0) {
399062095d54SToby Isaac         numPointsWithDofs++;
399162095d54SToby Isaac       }
399262095d54SToby Isaac     }
39939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs,&pointsWithDofs));
39944833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
3995e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3996e4a60869SToby Isaac 
39979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&dof));
39989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&cdof));
399962095d54SToby Isaac       if ((dof - cdof) > 0) {
4000e4a60869SToby Isaac         pointsWithDofs[offset++] = l;
400162095d54SToby Isaac       }
400262095d54SToby Isaac     }
40039566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
40049566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
400562095d54SToby Isaac   }
400662095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
40079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC-pStartC,&maxChildIds));
400862095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) {
400962095d54SToby Isaac     maxChildIds[p - pStartC] = -2;
401062095d54SToby Isaac   }
40119566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX));
40129566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX));
401362095d54SToby Isaac 
40149566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
40159566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
401662095d54SToby Isaac 
40179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse,&aSec,&aIS));
40189566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS,&anchors));
40199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd));
402062095d54SToby Isaac 
40219566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse,&cSec,&cMat,NULL));
40229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec,&cStart,&cEnd));
402362095d54SToby Isaac 
402462095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
40259566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootValuesSec));
40269566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec,pStartC,pEndC));
40279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse,&numFields));
402862095d54SToby Isaac   {
402962095d54SToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
40309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO));
403162095d54SToby Isaac   }
40320eb7e1eaSToby Isaac   if (grad) {
40330eb7e1eaSToby Isaac     PetscInt i;
40340eb7e1eaSToby Isaac 
40359566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom,&cellDM));
40369566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom,&cellGeomArray));
40379566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad,&gradDM));
40389566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad,&gradArray));
40390eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1,numFields); i++) {
40400eb7e1eaSToby Isaac       PetscObject  obj;
40410eb7e1eaSToby Isaac       PetscClassId id;
40420eb7e1eaSToby Isaac 
40439566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
40449566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj,&id));
40450eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
40460eb7e1eaSToby Isaac         fv      = (PetscFV) obj;
40479566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv,&numFVcomps));
40480eb7e1eaSToby Isaac         fvField = i;
40490eb7e1eaSToby Isaac         break;
40500eb7e1eaSToby Isaac       }
40510eb7e1eaSToby Isaac     }
40520eb7e1eaSToby Isaac   }
405362095d54SToby Isaac 
405462095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
405562095d54SToby Isaac     PetscInt dof;
405662095d54SToby Isaac     PetscInt maxChildId     = maxChildIds[p - pStartC];
405762095d54SToby Isaac     PetscInt numValues      = 0;
405862095d54SToby Isaac 
40599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
406062095d54SToby Isaac     if (dof < 0) {
406162095d54SToby Isaac       dof = -(dof + 1);
406262095d54SToby Isaac     }
406362095d54SToby Isaac     offsets[0]    = 0;
406462095d54SToby Isaac     newOffsets[0] = 0;
406562095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
406662095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
406762095d54SToby Isaac 
40689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
406962095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
407062095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
407162095d54SToby Isaac 
40729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse,c,&clDof));
407362095d54SToby Isaac         numValues += clDof;
407462095d54SToby Isaac       }
40759566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure));
407662095d54SToby Isaac     }
407762095d54SToby Isaac     else if (maxChildId == -1) {
40789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse,p,&numValues));
407962095d54SToby Isaac     }
408062095d54SToby Isaac     /* we will pack the column indices with the field offsets */
408178b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
40820eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
40830eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
40840eb7e1eaSToby Isaac     }
40859566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec,p,numValues));
408662095d54SToby Isaac   }
40879566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
408862095d54SToby Isaac   {
408962095d54SToby Isaac     PetscInt          numRootValues;
409062095d54SToby Isaac     const PetscScalar *coarseArray;
409162095d54SToby Isaac 
40929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec,&numRootValues));
40939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues,&rootValues));
40949566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal,&coarseArray));
409562095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
409662095d54SToby Isaac       PetscInt    numValues;
409762095d54SToby Isaac       PetscInt    pValOff;
409862095d54SToby Isaac       PetscScalar *pVal;
409962095d54SToby Isaac       PetscInt    maxChildId = maxChildIds[p - pStartC];
410062095d54SToby Isaac 
41019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec,p,&numValues));
410262095d54SToby Isaac       if (!numValues) {
410362095d54SToby Isaac         continue;
410462095d54SToby Isaac       }
41059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec,p,&pValOff));
410662095d54SToby Isaac       pVal = &(rootValues[pValOff]);
410762095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
41080eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
41099566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse,NULL,vecCoarseLocal,p,&closureSize,&pVal));
41100eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
4111193eb951SToby Isaac           PetscFVCellGeom *cg;
41126dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
41130eb7e1eaSToby Isaac           PetscInt        i;
41140eb7e1eaSToby Isaac 
41150eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
41160eb7e1eaSToby Isaac 
41179566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM,p,cellGeomArray,(void *) &cg));
41180eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
41190eb7e1eaSToby Isaac           pVal += dim;
41209566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM,p,gradArray,(void *) &gradVals));
41210eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
41220eb7e1eaSToby Isaac         }
412362095d54SToby Isaac       }
412478b7adb5SToby Isaac       else if (maxChildId == -1) {
412578b7adb5SToby Isaac         PetscInt lDof, lOff, i;
412678b7adb5SToby Isaac 
41279566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse,p,&lDof));
41289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse,p,&lOff));
412978b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
413078b7adb5SToby Isaac       }
413178b7adb5SToby Isaac     }
41329566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal,&coarseArray));
41339566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
413462095d54SToby Isaac   }
413562095d54SToby Isaac   {
413662095d54SToby Isaac     PetscSF  valuesSF;
413762095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
413862095d54SToby Isaac 
41399566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafValuesSec));
41409566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded,rootValuesSec,&remoteOffsetsValues,leafValuesSec));
41419566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded,rootValuesSec,remoteOffsetsValues,leafValuesSec,&valuesSF));
41429566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
41439566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
41449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec,&numLeafValues));
41459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues,&leafValues));
41469566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF,MPIU_SCALAR,rootValues,leafValues,MPI_REPLACE));
41479566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF,MPIU_SCALAR,rootValues,leafValues,MPI_REPLACE));
41489566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
41499566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
41509566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
415162095d54SToby Isaac   }
41529566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
415362095d54SToby Isaac   {
415462095d54SToby Isaac     PetscInt    maxDof;
415562095d54SToby Isaac     PetscInt    *rowIndices;
415662095d54SToby Isaac     DM           refTree;
415762095d54SToby Isaac     PetscInt     **refPointFieldN;
415862095d54SToby Isaac     PetscScalar  ***refPointFieldMats;
415962095d54SToby Isaac     PetscSection refConSec, refAnSec;
41600eb7e1eaSToby Isaac     PetscInt     pRefStart,pRefEnd,leafStart,leafEnd;
416162095d54SToby Isaac     PetscScalar  *pointWork;
416262095d54SToby Isaac 
41639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine,&maxDof));
41649566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
41659566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork));
41669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine,&refTree));
41679566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine,refTree));
41689566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
41699566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree,&refConSec,NULL,NULL));
41709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree,&refAnSec,NULL));
41719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd));
41729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd));
41739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine,0,&cellStart,&cellEnd));
41740eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
417562095d54SToby Isaac       PetscInt          gDof, gcDof, gOff, lDof;
417662095d54SToby Isaac       PetscInt          numValues, pValOff;
417762095d54SToby Isaac       PetscInt          childId;
417862095d54SToby Isaac       const PetscScalar *pVal;
41790eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
418062095d54SToby Isaac 
41819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine,p,&gDof));
41829566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine,p,&lDof));
41839566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine,p,&gcDof));
418462095d54SToby Isaac       if ((gDof - gcDof) <= 0) {
418562095d54SToby Isaac         continue;
418662095d54SToby Isaac       }
41879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine,p,&gOff));
41889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec,p,&numValues));
418962095d54SToby Isaac       if (!numValues) continue;
41909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec,p,&pValOff));
419162095d54SToby Isaac       pVal = &leafValues[pValOff];
419262095d54SToby Isaac       offsets[0]        = 0;
419362095d54SToby Isaac       offsetsCopy[0]    = 0;
419462095d54SToby Isaac       newOffsets[0]     = 0;
419562095d54SToby Isaac       newOffsetsCopy[0] = 0;
41964833aeb0SToby Isaac       childId           = cids[p - pStartF];
419762095d54SToby Isaac       if (numFields) {
419862095d54SToby Isaac         PetscInt f;
419962095d54SToby Isaac         for (f = 0; f < numFields; f++) {
420062095d54SToby Isaac           PetscInt rowDof;
420162095d54SToby Isaac 
42029566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine,p,f,&rowDof));
420362095d54SToby Isaac           offsets[f + 1]        = offsets[f] + rowDof;
420462095d54SToby Isaac           offsetsCopy[f + 1]    = offsets[f + 1];
420562095d54SToby Isaac           /* TODO: closure indices */
42069f4e70e1SToby Isaac           newOffsets[f + 1]     = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
420762095d54SToby Isaac         }
42089566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,rowIndices));
420962095d54SToby Isaac       }
421062095d54SToby Isaac       else {
42114833aeb0SToby Isaac         offsets[0]    = 0;
42124833aeb0SToby Isaac         offsets[1]    = lDof;
42134833aeb0SToby Isaac         newOffsets[0] = 0;
42144833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
42159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine,PETSC_FALSE,p,gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,rowIndices));
421662095d54SToby Isaac       }
421762095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
42189566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine,numValues,rowIndices,pVal,INSERT_VALUES));
421962095d54SToby Isaac       } else {
422062095d54SToby Isaac         PetscInt f;
422162095d54SToby Isaac 
422278b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
422378b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
422478b7adb5SToby Isaac           fvGradData = &pVal[numValues];
422578b7adb5SToby Isaac         }
422662095d54SToby Isaac         for (f = 0; f < PetscMax(1,numFields); f++) {
422762095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
422862095d54SToby Isaac           PetscInt numRows = offsets[f+1] - offsets[f];
422962095d54SToby Isaac           PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
423062095d54SToby Isaac           const PetscScalar *cVal = &pVal[newOffsets[f]];
423162095d54SToby Isaac           PetscScalar *rVal = &pointWork[offsets[f]];
423262095d54SToby Isaac           PetscInt i, j;
423362095d54SToby Isaac 
4234708c7f19SToby Isaac #if 0
423563a3b9bcSJacob Faibussowitsch           PetscCall(PetscInfo(coarse,"childId %" PetscInt_FMT ", numRows %" PetscInt_FMT ", numCols %" PetscInt_FMT ", refPointFieldN %" PetscInt_FMT " maxDof %" PetscInt_FMT "\n",childId,numRows,numCols,refPointFieldN[childId - pRefStart][f], maxDof));
4236708c7f19SToby Isaac #endif
423762095d54SToby Isaac           for (i = 0; i < numRows; i++) {
423862095d54SToby Isaac             PetscScalar val = 0.;
423962095d54SToby Isaac             for (j = 0; j < numCols; j++) {
424062095d54SToby Isaac               val += childMat[i * numCols + j] * cVal[j];
424162095d54SToby Isaac             }
424262095d54SToby Isaac             rVal[i] = val;
424362095d54SToby Isaac           }
42440eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
42450eb7e1eaSToby Isaac             PetscReal   centroid[3];
42460eb7e1eaSToby Isaac             PetscScalar diff[3];
42470eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
42480eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
42490eb7e1eaSToby Isaac 
42509566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL));
42510eb7e1eaSToby Isaac             for (i = 0; i < dim; i++) {
42520eb7e1eaSToby Isaac               diff[i] = centroid[i] - parentCentroid[i];
42530eb7e1eaSToby Isaac             }
42540eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
42550eb7e1eaSToby Isaac               PetscScalar val = 0.;
42560eb7e1eaSToby Isaac 
425789698031SToby Isaac               for (j = 0; j < dim; j++) {
42580eb7e1eaSToby Isaac                 val += gradient[dim * i + j] * diff[j];
42590eb7e1eaSToby Isaac               }
42600eb7e1eaSToby Isaac               rVal[i] += val;
42610eb7e1eaSToby Isaac             }
42620eb7e1eaSToby Isaac           }
42639566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,INSERT_VALUES));
426462095d54SToby Isaac         }
426562095d54SToby Isaac       }
426662095d54SToby Isaac     }
42679566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN));
42689566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine,maxDof,MPIU_SCALAR,&pointWork));
42699566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine,maxDof,MPIU_INT,&rowIndices));
427062095d54SToby Isaac   }
42719566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
42729566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
42739566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO));
42749566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS,&anchors));
4275ebf164c7SToby Isaac   PetscFunctionReturn(0);
4276ebf164c7SToby Isaac }
4277ebf164c7SToby Isaac 
4278ebf164c7SToby Isaac static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4279ebf164c7SToby Isaac {
4280c921d74cSToby Isaac   DM             refTree;
4281c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4282c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4283c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4284c921d74cSToby Isaac   PetscSection   cSecRef;
4285c921d74cSToby Isaac   PetscInt       *parentIndices, pRefStart, pRefEnd;
4286d3bc4906SToby Isaac   PetscScalar    *rootValues, *parentValues;
4287c921d74cSToby Isaac   Mat            injRef;
4288c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4289c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4290c921d74cSToby Isaac   PetscInt       *offsets, *offsetsCopy, *rowOffsets;
4291c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4292c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4293c921d74cSToby Isaac   PetscScalar    ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4294c921d74cSToby Isaac 
4295ebf164c7SToby Isaac   PetscFunctionBegin;
4296c921d74cSToby Isaac 
4297c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
42989566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE));
42999566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE));
43009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse,&refTree));
43019566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse,refTree));
43029566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree,&cSecRef,NULL,NULL));
43039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd));
43049566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree,&injRef));
4305c921d74cSToby Isaac 
43069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine,&pStartF,&pEndF));
43079566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine,&localFine));
43089566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine,&globalFine));
43099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine,&numFields));
43109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse,&pStartC,&pEndC));
43119566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse,&localCoarse));
43129566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse,&globalCoarse));
43139566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse,&maxDof));
4314c921d74cSToby Isaac   {
4315c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1,numFields) + 1;
43169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets));
4317c921d74cSToby Isaac   }
4318c921d74cSToby Isaac 
43199566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues));
4320c921d74cSToby Isaac 
43219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues));
4322c921d74cSToby Isaac 
4323c921d74cSToby Isaac   /* count indices */
43249566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine,&colMap));
43259566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse,&rowMap));
43269566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
43279566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
43289566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap,&rowStart,&rowEnd));
43299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap,&colStart,&colEnd));
4330c921d74cSToby Isaac   /* insert values */
43319566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats));
4332c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4333c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
433478b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4335c921d74cSToby Isaac 
43369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse,p,&dof));
43379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse,p,&cdof));
4338c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
43399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse,p,&dof));
43409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse,p,&gOff));
4341c921d74cSToby Isaac 
4342c921d74cSToby Isaac     rowOffsets[0] = 0;
4343c921d74cSToby Isaac     offsetsCopy[0] = 0;
4344c921d74cSToby Isaac     if (numFields) {
4345c921d74cSToby Isaac       PetscInt f;
4346c921d74cSToby Isaac 
4347c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4348c921d74cSToby Isaac         PetscInt fDof;
43499566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse,p,f,&fDof));
4350c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4351c921d74cSToby Isaac       }
43529566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,-1,NULL,parentIndices));
4353367003a6SStefano Zampini     } else {
43549566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse,PETSC_FALSE,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,NULL,NULL,parentIndices));
4355c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4356c921d74cSToby Isaac     }
4357c921d74cSToby Isaac 
43589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec,p,&numLeaves));
43599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec,p,&leafStart));
4360c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
43612f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4362c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4363c921d74cSToby Isaac       PetscInt numIndices, childId, offset;
4364c921d74cSToby Isaac       const PetscScalar *childValues;
4365c921d74cSToby Isaac 
43669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec,l,&numIndices));
43679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec,l,&offset));
4368c921d74cSToby Isaac       childId = (PetscInt) PetscRealPart(rootValues[offset++]);
4369c921d74cSToby Isaac       childValues = &rootValues[offset];
4370c921d74cSToby Isaac       numIndices--;
4371c921d74cSToby Isaac 
4372c921d74cSToby Isaac       if (childId == -2) { /* skip */
4373c921d74cSToby Isaac         continue;
4374c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
43752f65e181SToby Isaac         PetscInt m;
43762f65e181SToby Isaac 
437778b7adb5SToby Isaac         contribute = PETSC_TRUE;
43782f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4379beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4380d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4381d3bc4906SToby Isaac 
438278b7adb5SToby Isaac         contribute = PETSC_TRUE;
43839566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree,childId,&parentId,NULL));
4384d3bc4906SToby Isaac 
4385d3bc4906SToby Isaac         lim = PetscMax(1,numFields);
4386d3bc4906SToby Isaac         offsets[0] = 0;
4387d3bc4906SToby Isaac         if (numFields) {
4388d3bc4906SToby Isaac           PetscInt f;
4389d3bc4906SToby Isaac 
4390d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4391d3bc4906SToby Isaac             PetscInt fDof;
43929566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef,childId,f,&fDof));
4393d3bc4906SToby Isaac 
4394d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4395d3bc4906SToby Isaac           }
4396d3bc4906SToby Isaac         }
4397d3bc4906SToby Isaac         else {
4398d3bc4906SToby Isaac           PetscInt cDof;
4399d3bc4906SToby Isaac 
44009566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef,childId,&cDof));
4401d3bc4906SToby Isaac           offsets[1] = cDof;
4402d3bc4906SToby Isaac         }
4403d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4404d3bc4906SToby Isaac           PetscScalar       *childMat   = &childrenMats[childId - pRefStart][f][0];
4405d3bc4906SToby Isaac           PetscInt          n           = offsets[f+1]-offsets[f];
4406e328ff09SToby Isaac           PetscInt          m           = rowOffsets[f+1]-rowOffsets[f];
4407d3bc4906SToby Isaac           PetscInt          i, j;
4408d3bc4906SToby Isaac           const PetscScalar *colValues  = &childValues[offsets[f]];
4409d3bc4906SToby Isaac 
4410e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4411d3bc4906SToby Isaac             PetscScalar val = 0.;
4412d3bc4906SToby Isaac             for (j = 0; j < n; j++) {
4413d3bc4906SToby Isaac               val += childMat[n * i + j] * colValues[j];
4414d3bc4906SToby Isaac             }
4415e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4416d3bc4906SToby Isaac           }
4417d3bc4906SToby Isaac         }
4418c921d74cSToby Isaac       }
4419c921d74cSToby Isaac     }
44209566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse,dof,parentIndices,parentValues,INSERT_VALUES));
4421c921d74cSToby Isaac   }
44229566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
44239566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
44249566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices,parentValues));
44259566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats));
44269566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
44279566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets,offsetsCopy,rowOffsets));
4428ebf164c7SToby Isaac   PetscFunctionReturn(0);
4429ebf164c7SToby Isaac }
4430ebf164c7SToby Isaac 
4431ff1f73f7SToby Isaac /*@
4432ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4433ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4434ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4435ff1f73f7SToby Isaac 
4436ff1f73f7SToby Isaac   collective
4437ff1f73f7SToby Isaac 
4438ff1f73f7SToby Isaac   Input Parameters:
4439ff1f73f7SToby Isaac + dmIn        - The DMPlex mesh for the input vector
4440ff1f73f7SToby Isaac . vecIn       - The input vector
4441ff1f73f7SToby Isaac . sfRefine    - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4442ff1f73f7SToby Isaac                 the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4443ff1f73f7SToby Isaac . sfCoarsen   - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4444ff1f73f7SToby Isaac                 the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4445ff1f73f7SToby Isaac . cidsRefine  - The childIds of the points in dmOut.  These childIds relate back to the reference tree: childid[j] = k implies
4446ff1f73f7SToby Isaac                 that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4447ff1f73f7SToby Isaac                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in dmOut is exactly
4448ff1f73f7SToby Isaac                 equivalent to its root in dmIn, so no interpolation is necessary.  childid[j] = -2 indicates that this
4449ff1f73f7SToby Isaac                 point j in dmOut is not a leaf of sfRefine.
4450ff1f73f7SToby Isaac . cidsCoarsen - The childIds of the points in dmIn.  These childIds relate back to the reference tree: childid[j] = k implies
4451ff1f73f7SToby Isaac                 that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4452ff1f73f7SToby Isaac                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4453ff1f73f7SToby Isaac . useBCs      - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4454ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4455ff1f73f7SToby Isaac 
4456ff1f73f7SToby Isaac   Output Parameters:
44578966356dSPierre Jolivet . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
4458ff1f73f7SToby Isaac                 projection of vecIn from dmIn to dmOut.  Note that any field discretized with a PetscFV finite volume
4459ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4460ff1f73f7SToby Isaac                 coarse points to fine points.
4461ff1f73f7SToby Isaac 
4462ff1f73f7SToby Isaac   Level: developer
4463ff1f73f7SToby Isaac 
4464db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4465ff1f73f7SToby Isaac @*/
4466ff1f73f7SToby Isaac PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
446738fc2455SToby Isaac {
446838fc2455SToby Isaac   PetscFunctionBegin;
44699566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut,0.0));
4470ff1f73f7SToby Isaac   if (sfRefine) {
4471fbfa57b9SToby Isaac     Vec vecInLocal;
44720eb7e1eaSToby Isaac     DM  dmGrad = NULL;
44730eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4474fbfa57b9SToby Isaac 
44759566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn,&vecInLocal));
44769566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal,0.0));
44770eb7e1eaSToby Isaac     {
44780eb7e1eaSToby Isaac       PetscInt  numFields, i;
44790eb7e1eaSToby Isaac 
44809566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
44810eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
44820eb7e1eaSToby Isaac         PetscObject  obj;
44830eb7e1eaSToby Isaac         PetscClassId classid;
44840eb7e1eaSToby Isaac 
44859566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
44869566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
44870eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
44889566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad));
44890eb7e1eaSToby Isaac           break;
44900eb7e1eaSToby Isaac         }
44910eb7e1eaSToby Isaac       }
44920eb7e1eaSToby Isaac     }
44931baa6e33SBarry Smith     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL));
44949566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal));
44959566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal));
44960eb7e1eaSToby Isaac     if (dmGrad) {
44979566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad,&grad));
44989566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad));
44990eb7e1eaSToby Isaac     }
45009566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfRefine,cidsRefine,grad,cellGeom));
45019566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn,&vecInLocal));
45020eb7e1eaSToby Isaac     if (dmGrad) {
45039566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmGrad,&grad));
45040eb7e1eaSToby Isaac     }
4505ebf164c7SToby Isaac   }
45061baa6e33SBarry Smith   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfCoarsen,cidsCoarsen));
45079566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
45089566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
450938fc2455SToby Isaac   PetscFunctionReturn(0);
451038fc2455SToby Isaac }
4511