xref: /petsc/src/dm/impls/plex/plextree.c (revision 8112c1cbf372cb53bf7c5aca994a84a6a303db4d)
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 
1220f4b53cSBarry Smith   Not Collective
13d6a7ad0dSToby Isaac 
14d6a7ad0dSToby Isaac   Input Parameters:
15a1cb98faSBarry Smith + dm  - The `DMPLEX` object
16a1cb98faSBarry Smith - ref - The reference tree `DMPLEX` object
17d6a7ad0dSToby Isaac 
180b7167a0SToby Isaac   Level: intermediate
19d6a7ad0dSToby Isaac 
201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`,`DMPlexGetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
21d6a7ad0dSToby Isaac @*/
DMPlexSetReferenceTree(DM dm,DM ref)22d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
23d71ae5a4SJacob Faibussowitsch {
24d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
25d6a7ad0dSToby Isaac 
26d6a7ad0dSToby Isaac   PetscFunctionBegin;
27d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28ad540459SPierre Jolivet   if (ref) PetscValidHeaderSpecific(ref, DM_CLASSID, 2);
299566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)ref));
309566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&mesh->referenceTree));
31d6a7ad0dSToby Isaac   mesh->referenceTree = ref;
323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33d6a7ad0dSToby Isaac }
34d6a7ad0dSToby Isaac 
35d6a7ad0dSToby Isaac /*@
36d6a7ad0dSToby Isaac   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.
37d6a7ad0dSToby Isaac 
3820f4b53cSBarry Smith   Not Collective
39d6a7ad0dSToby Isaac 
402fe279fdSBarry Smith   Input Parameter:
41a1cb98faSBarry Smith . dm - The `DMPLEX` object
42d6a7ad0dSToby Isaac 
432fe279fdSBarry Smith   Output Parameter:
44a1cb98faSBarry Smith . ref - The reference tree `DMPLEX` object
45d6a7ad0dSToby Isaac 
460b7167a0SToby Isaac   Level: intermediate
47d6a7ad0dSToby Isaac 
48d3a532e9SStefano Zampini   Developer Notes:
49d3a532e9SStefano Zampini   The reference tree is shallow copied during `DMClone()`, thus it is may be shared by different `DM`s.
50d3a532e9SStefano Zampini   It is not a topological-only object, since some parts of the library use its local section to compute
51d3a532e9SStefano Zampini   interpolation and injection matrices. This may lead to unexpected failures during those calls.
52d3a532e9SStefano Zampini 
531cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
54d6a7ad0dSToby Isaac @*/
DMPlexGetReferenceTree(DM dm,DM * ref)55d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
56d71ae5a4SJacob Faibussowitsch {
57d6a7ad0dSToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
58d6a7ad0dSToby Isaac 
59d6a7ad0dSToby Isaac   PetscFunctionBegin;
60d6a7ad0dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
614f572ea9SToby Isaac   PetscAssertPointer(ref, 2);
62d6a7ad0dSToby Isaac   *ref = mesh->referenceTree;
633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64d6a7ad0dSToby Isaac }
65d6a7ad0dSToby Isaac 
DMPlexReferenceTreeGetChildSymmetry_Default(DM dm,PetscInt parent,PetscInt parentOrientA,PetscInt childOrientA,PetscInt childA,PetscInt parentOrientB,PetscInt * childOrientB,PetscInt * childB)66d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
67d71ae5a4SJacob Faibussowitsch {
68dcbd3bf7SToby Isaac   PetscInt coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
69dcbd3bf7SToby Isaac 
70dcbd3bf7SToby Isaac   PetscFunctionBegin;
71dcbd3bf7SToby Isaac   if (parentOrientA == parentOrientB) {
72dcbd3bf7SToby Isaac     if (childOrientB) *childOrientB = childOrientA;
73dcbd3bf7SToby Isaac     if (childB) *childB = childA;
743ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
75dcbd3bf7SToby Isaac   }
76dcbd3bf7SToby Isaac   for (dim = 0; dim < 3; dim++) {
779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
78ad540459SPierre Jolivet     if (parent >= dStart && parent <= dEnd) break;
79dcbd3bf7SToby Isaac   }
8063a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
8128b400f6SJacob Faibussowitsch   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
82dcbd3bf7SToby Isaac   if (childA < dStart || childA >= dEnd) {
83dcbd3bf7SToby Isaac     /* this is a lower-dimensional child: bootstrap */
84dcbd3bf7SToby Isaac     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
85dcbd3bf7SToby Isaac     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
86dcbd3bf7SToby Isaac 
879566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, childA, &supp));
89dcbd3bf7SToby Isaac 
90dcbd3bf7SToby Isaac     /* find a point sA in supp(childA) that has the same parent */
91dcbd3bf7SToby Isaac     for (i = 0; i < size; i++) {
92dcbd3bf7SToby Isaac       PetscInt sParent;
93dcbd3bf7SToby Isaac 
94dcbd3bf7SToby Isaac       sA = supp[i];
95dcbd3bf7SToby Isaac       if (sA == parent) continue;
969566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
97ad540459SPierre Jolivet       if (sParent == parent) break;
98dcbd3bf7SToby Isaac     }
9908401ef6SPierre Jolivet     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
100dcbd3bf7SToby Isaac     /* find out which point sB is in an equivalent position to sA under
101dcbd3bf7SToby Isaac      * parentOrientB */
1029566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildSymmetry_Default(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
1039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
1049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sA, &coneA));
1059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sB, &coneB));
1069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
1079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
108dcbd3bf7SToby Isaac     /* step through the cone of sA in natural order */
109dcbd3bf7SToby Isaac     for (i = 0; i < sConeSize; i++) {
110dcbd3bf7SToby Isaac       if (coneA[i] == childA) {
111dcbd3bf7SToby Isaac         /* if childA is at position i in coneA,
112dcbd3bf7SToby Isaac          * then we want the point that is at sOrientB*i in coneB */
113dcbd3bf7SToby Isaac         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
114dcbd3bf7SToby Isaac         if (childB) *childB = coneB[j];
115dcbd3bf7SToby Isaac         if (childOrientB) {
116b5a892a1SMatthew G. Knepley           DMPolytopeType ct;
117dcbd3bf7SToby Isaac           PetscInt       oBtrue;
118dcbd3bf7SToby Isaac 
1199566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
120dcbd3bf7SToby Isaac           /* compose sOrientB and oB[j] */
1211dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
122b5a892a1SMatthew G. Knepley           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
123dcbd3bf7SToby Isaac           /* we may have to flip an edge */
124b5a892a1SMatthew G. Knepley           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]);
125b5a892a1SMatthew G. Knepley           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
126b5a892a1SMatthew G. Knepley           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
127dcbd3bf7SToby Isaac           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
128dcbd3bf7SToby Isaac         }
129dcbd3bf7SToby Isaac         break;
130dcbd3bf7SToby Isaac       }
131dcbd3bf7SToby Isaac     }
13208401ef6SPierre Jolivet     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
1333ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
134dcbd3bf7SToby Isaac   }
135dcbd3bf7SToby Isaac   /* get the cone size and symmetry swap */
1369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
137dcbd3bf7SToby Isaac   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
138dcbd3bf7SToby Isaac   if (dim == 2) {
139dcbd3bf7SToby Isaac     /* orientations refer to cones: we want them to refer to vertices:
140dcbd3bf7SToby Isaac      * if it's a rotation, they are the same, but if the order is reversed, a
141dcbd3bf7SToby Isaac      * permutation that puts side i first does *not* put vertex i first */
142dcbd3bf7SToby Isaac     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
143dcbd3bf7SToby Isaac     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
144dcbd3bf7SToby Isaac     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
145947b95d8SBarry Smith   } else {
146dcbd3bf7SToby Isaac     ABswapVert = ABswap;
147dcbd3bf7SToby Isaac   }
148dcbd3bf7SToby Isaac   if (childB) {
149dcbd3bf7SToby Isaac     /* assume that each child corresponds to a vertex, in the same order */
150dcbd3bf7SToby Isaac     PetscInt        p, posA = -1, numChildren, i;
151dcbd3bf7SToby Isaac     const PetscInt *children;
152dcbd3bf7SToby Isaac 
153dcbd3bf7SToby Isaac     /* count which position the child is in */
1549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
155dcbd3bf7SToby Isaac     for (i = 0; i < numChildren; i++) {
156dcbd3bf7SToby Isaac       p = children[i];
157dcbd3bf7SToby Isaac       if (p == childA) {
158dcbd3bf7SToby Isaac         posA = i;
159dcbd3bf7SToby Isaac         break;
160dcbd3bf7SToby Isaac       }
161dcbd3bf7SToby Isaac     }
162dcbd3bf7SToby Isaac     if (posA >= coneSize) {
163dcbd3bf7SToby Isaac       /* this is the triangle in the middle of a uniformly refined triangle: it
164dcbd3bf7SToby Isaac        * is invariant */
1651dca8a05SBarry Smith       PetscCheck(dim == 2 && posA == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected a middle triangle, got something else");
166dcbd3bf7SToby Isaac       *childB = childA;
1679371c9d4SSatish Balay     } 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);
1763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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:
183a1cb98faSBarry Smith + 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:
19120f4b53cSBarry Smith + childOrientB - if not `NULL`, set to the new orientation for describing the child
19220f4b53cSBarry Smith - childB       - if not `NULL`, the new childID for describing the child
193dcbd3bf7SToby Isaac 
194dcbd3bf7SToby Isaac   Level: developer
195dcbd3bf7SToby Isaac 
1961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetReferenceTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetTree()`
197dcbd3bf7SToby Isaac @*/
DMPlexReferenceTreeGetChildSymmetry(DM dm,PetscInt parent,PetscInt parentOrientA,PetscInt childOrientA,PetscInt childA,PetscInt parentOrientB,PetscInt * childOrientB,PetscInt * childB)198d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
199d71ae5a4SJacob Faibussowitsch {
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));
2063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
207dcbd3bf7SToby Isaac }
208dcbd3bf7SToby Isaac 
209776742edSToby Isaac static PetscErrorCode DMPlexSetTree_Internal(DM, PetscSection, PetscInt *, PetscInt *, PetscBool, PetscBool);
210f9f063d4SToby Isaac 
DMPlexCreateReferenceTree_SetTree(DM dm,PetscSection parentSection,PetscInt parents[],PetscInt childIDs[])211d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
212d71ae5a4SJacob Faibussowitsch {
213f2c1aa1dSLisandro Dalcin   PetscFunctionBegin;
2149566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_TRUE, PETSC_FALSE));
2153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
216f2c1aa1dSLisandro Dalcin }
217f2c1aa1dSLisandro Dalcin 
DMPlexCreateReferenceTree_Union(DM K,DM Kref,const char * labelName,DM * ref)218d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
219d71ae5a4SJacob Faibussowitsch {
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 */
23848a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; p++) PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1));
239da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
240da43764aSToby Isaac     PetscInt q, qSize;
2419566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(identityRef, p, &q));
2429566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize));
24348a46eb9SPierre Jolivet     if (qSize > 1) PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1));
244da43764aSToby Isaac   }
2459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart, &permvals));
246da43764aSToby Isaac   offset = 0;
247da43764aSToby Isaac   /* stratify points in the union by topological dimension */
248da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
249da43764aSToby Isaac     PetscInt cStart, cEnd, c;
250da43764aSToby Isaac 
2519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
252ad540459SPierre Jolivet     for (c = cStart; c < cEnd; c++) permvals[offset++] = c;
253da43764aSToby Isaac 
2549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
255ad540459SPierre Jolivet     for (c = cStart; c < cEnd; c++) permvals[offset++] = c + (pEnd - pStart);
256da43764aSToby Isaac   }
2579566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
2589566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetPermutation(unionSection, perm));
2599566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionSection));
2609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionSection, &numUnionPoints));
2619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numUnionPoints, &coneSizes, dim + 1, &numDimPoints));
262da43764aSToby Isaac   /* count dimension points */
263da43764aSToby Isaac   for (d = 0; d <= dim; d++) {
264da43764aSToby Isaac     PetscInt cStart, cOff, cOff2;
2659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, NULL));
2669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff));
267da43764aSToby Isaac     if (d < dim) {
2689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d + 1, &cStart, NULL));
2699566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff2));
2709371c9d4SSatish Balay     } else {
271da43764aSToby Isaac       cOff2 = numUnionPoints;
272da43764aSToby Isaac     }
273da43764aSToby Isaac     numDimPoints[dim - d] = cOff2 - cOff;
274da43764aSToby Isaac   }
2759566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &unionConeSection));
2769566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(unionConeSection, 0, numUnionPoints));
277da43764aSToby Isaac   /* count the cones in the union */
278da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
279da43764aSToby Isaac     PetscInt dof, uOff;
280da43764aSToby Isaac 
2819566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
2829566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
2839566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
284da43764aSToby Isaac     coneSizes[uOff] = dof;
285da43764aSToby Isaac   }
286da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
287da43764aSToby Isaac     PetscInt dof, uDof, uOff;
288da43764aSToby Isaac 
2899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
2909566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
2919566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
292da43764aSToby Isaac     if (uDof) {
2939566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
294da43764aSToby Isaac       coneSizes[uOff] = dof;
295da43764aSToby Isaac     }
296da43764aSToby Isaac   }
2979566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(unionConeSection));
2989566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(unionConeSection, &numCones));
2999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(numCones, &unionCones, numCones, &unionOrientations));
300da43764aSToby Isaac   /* write the cones in the union */
301da43764aSToby Isaac   for (p = pStart; p < pEnd; p++) {
302da43764aSToby Isaac     PetscInt        dof, uOff, c, cOff;
303da43764aSToby Isaac     const PetscInt *cone, *orientation;
304da43764aSToby Isaac 
3059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(K, p, &dof));
3069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(K, p, &cone));
3079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(K, p, &orientation));
3089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
3099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
310da43764aSToby Isaac     for (c = 0; c < dof; c++) {
311da43764aSToby Isaac       PetscInt e, eOff;
312da43764aSToby Isaac       e = cone[c];
3139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
314da43764aSToby Isaac       unionCones[cOff + c]        = eOff;
315da43764aSToby Isaac       unionOrientations[cOff + c] = orientation[c];
316da43764aSToby Isaac     }
317da43764aSToby Isaac   }
318da43764aSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
319da43764aSToby Isaac     PetscInt        dof, uDof, uOff, c, cOff;
320da43764aSToby Isaac     const PetscInt *cone, *orientation;
321da43764aSToby Isaac 
3229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
3239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(Kref, p, &cone));
3249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation));
3259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
327da43764aSToby Isaac     if (uDof) {
3289566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
329da43764aSToby Isaac       for (c = 0; c < dof; c++) {
330da43764aSToby Isaac         PetscInt e, eOff, eDof;
331da43764aSToby Isaac 
332da43764aSToby Isaac         e = cone[c];
3339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart), &eDof));
334da43764aSToby Isaac         if (eDof) {
3359566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
3369371c9d4SSatish Balay         } else {
3379566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(identityRef, e, &e));
3389566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
339da43764aSToby Isaac         }
340da43764aSToby Isaac         unionCones[cOff + c]        = eOff;
341da43764aSToby Isaac         unionOrientations[cOff + c] = orientation[c];
342da43764aSToby Isaac       }
343da43764aSToby Isaac     }
344da43764aSToby Isaac   }
345da43764aSToby Isaac   /* get the coordinates */
346da43764aSToby Isaac   {
347da43764aSToby Isaac     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
348da43764aSToby Isaac     PetscSection KcoordsSec, KrefCoordsSec;
349da43764aSToby Isaac     Vec          KcoordsVec, KrefCoordsVec;
350da43764aSToby Isaac     PetscScalar *Kcoords;
351da43764aSToby Isaac 
3529566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(K, &KcoordsSec));
3539566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec));
3549566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec));
3559566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));
356da43764aSToby Isaac 
357da43764aSToby Isaac     numVerts = numDimPoints[0];
3589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numVerts * dim, &unionCoords));
3599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd));
360da43764aSToby Isaac 
361da43764aSToby Isaac     offset = 0;
362da43764aSToby Isaac     for (v = vStart; v < vEnd; v++) {
3639566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pStart, &vOff));
3649566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords));
365ad540459SPierre Jolivet       for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
366da43764aSToby Isaac       offset++;
367da43764aSToby Isaac     }
3689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(Kref, 0, &vRefStart, &vRefEnd));
369da43764aSToby Isaac     for (v = vRefStart; v < vRefEnd; v++) {
3709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(unionSection, v - pRefStart + (pEnd - pStart), &vDof));
3719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, v - pRefStart + (pEnd - pStart), &vOff));
3729566063dSJacob Faibussowitsch       PetscCall(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords));
373da43764aSToby Isaac       if (vDof) {
374ad540459SPierre Jolivet         for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
375da43764aSToby Isaac         offset++;
376da43764aSToby Isaac       }
377da43764aSToby Isaac     }
378da43764aSToby Isaac   }
3799566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, ref));
3809566063dSJacob Faibussowitsch   PetscCall(DMSetType(*ref, DMPLEX));
3819566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ref, dim));
3829566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromDAG(*ref, dim, numDimPoints, coneSizes, unionCones, unionOrientations, unionCoords));
38310f7e118SToby Isaac   /* set the tree */
3849566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &parentSection));
3859566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(parentSection, 0, numUnionPoints));
38610f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
38710f7e118SToby Isaac     PetscInt uDof, uOff;
38810f7e118SToby Isaac 
3899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
3909566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
3911baa6e33SBarry Smith     if (uDof) PetscCall(PetscSectionSetDof(parentSection, uOff, 1));
39210f7e118SToby Isaac   }
3939566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(parentSection));
3949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &parentSize));
3959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(parentSize, &parents, parentSize, &childIDs));
39610f7e118SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
39710f7e118SToby Isaac     PetscInt uDof, uOff;
39810f7e118SToby Isaac 
3999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
4009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
40110f7e118SToby Isaac     if (uDof) {
40210f7e118SToby Isaac       PetscInt pOff, parent, parentU;
4039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(parentSection, uOff, &pOff));
4049566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(identityRef, p, &parent));
4059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(unionSection, parent - pStart, &parentU));
40610f7e118SToby Isaac       parents[pOff]  = parentU;
40710f7e118SToby Isaac       childIDs[pOff] = uOff;
40810f7e118SToby Isaac     }
40910f7e118SToby Isaac   }
4109566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_SetTree(*ref, parentSection, parents, childIDs));
4119566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
4129566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parents, childIDs));
41310f7e118SToby Isaac 
414da43764aSToby Isaac   /* clean up */
4159566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionSection));
4169566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&unionConeSection));
4179566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&perm));
4189566063dSJacob Faibussowitsch   PetscCall(PetscFree(unionCoords));
4199566063dSJacob Faibussowitsch   PetscCall(PetscFree2(unionCones, unionOrientations));
4209566063dSJacob Faibussowitsch   PetscCall(PetscFree2(coneSizes, numDimPoints));
4213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4220e2cc29aSToby Isaac }
4230e2cc29aSToby Isaac 
4240e2cc29aSToby Isaac /*@
4250e2cc29aSToby Isaac   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.
4260e2cc29aSToby Isaac 
427d083f849SBarry Smith   Collective
4280e2cc29aSToby Isaac 
4290e2cc29aSToby Isaac   Input Parameters:
4300e2cc29aSToby Isaac + comm    - the MPI communicator
4310e2cc29aSToby Isaac . dim     - the spatial dimension
4320e2cc29aSToby Isaac - simplex - Flag for simplex, otherwise use a tensor-product cell
4330e2cc29aSToby Isaac 
4342fe279fdSBarry Smith   Output Parameter:
435a1cb98faSBarry Smith . ref - the reference tree `DMPLEX` object
4360e2cc29aSToby Isaac 
4370e2cc29aSToby Isaac   Level: intermediate
4380e2cc29aSToby Isaac 
439db781477SPatrick Sanan .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`
4400e2cc29aSToby Isaac @*/
DMPlexCreateDefaultReferenceTree(MPI_Comm comm,PetscInt dim,PetscBool simplex,DM * ref)441d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
442d71ae5a4SJacob Faibussowitsch {
4430e2cc29aSToby Isaac   DM_Plex *mesh;
4440e2cc29aSToby Isaac   DM       K, Kref;
4450e2cc29aSToby Isaac   PetscInt p, pStart, pEnd;
4460e2cc29aSToby Isaac   DMLabel  identity;
4470e2cc29aSToby Isaac 
4480e2cc29aSToby Isaac   PetscFunctionBegin;
4490e2cc29aSToby Isaac #if 1
4500e2cc29aSToby Isaac   comm = PETSC_COMM_SELF;
4510e2cc29aSToby Isaac #endif
4520e2cc29aSToby Isaac   /* create a reference element */
4539566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
4549566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(K, "identity"));
4559566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(K, "identity", &identity));
4569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
45748a46eb9SPierre Jolivet   for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(identity, p, p));
4580e2cc29aSToby Isaac   /* refine it */
4599566063dSJacob Faibussowitsch   PetscCall(DMRefine(K, comm, &Kref));
4600e2cc29aSToby Isaac 
4610e2cc29aSToby Isaac   /* the reference tree is the union of these two, without duplicating
4620e2cc29aSToby Isaac    * points that appear in both */
4639566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
4640e2cc29aSToby Isaac   mesh                   = (DM_Plex *)(*ref)->data;
4650e2cc29aSToby Isaac   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
4669566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
4679566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&Kref));
4683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
469da43764aSToby Isaac }
470da43764aSToby Isaac 
DMPlexTreeSymmetrize(DM dm)471d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
472d71ae5a4SJacob Faibussowitsch {
473878b19aaSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
474878b19aaSToby Isaac   PetscSection childSec, pSec;
4751690c2aeSBarry Smith   PetscInt     p, pSize, cSize, parMax = PETSC_INT_MIN, parMin = PETSC_INT_MAX;
476878b19aaSToby Isaac   PetscInt    *offsets, *children, pStart, pEnd;
477878b19aaSToby Isaac 
478878b19aaSToby Isaac   PetscFunctionBegin;
479878b19aaSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4809566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->childSection));
4819566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->children));
482878b19aaSToby Isaac   pSec = mesh->parentSection;
4833ba16761SJacob Faibussowitsch   if (!pSec) PetscFunctionReturn(PETSC_SUCCESS);
4849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(pSec, &pSize));
485878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
486878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
487878b19aaSToby Isaac 
488878b19aaSToby Isaac     parMax = PetscMax(parMax, par + 1);
489878b19aaSToby Isaac     parMin = PetscMin(parMin, par);
490878b19aaSToby Isaac   }
491878b19aaSToby Isaac   if (parMin > parMax) {
492878b19aaSToby Isaac     parMin = -1;
493878b19aaSToby Isaac     parMax = -1;
494878b19aaSToby Isaac   }
4959566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)pSec), &childSec));
4969566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(childSec, parMin, parMax));
497878b19aaSToby Isaac   for (p = 0; p < pSize; p++) {
498878b19aaSToby Isaac     PetscInt par = mesh->parents[p];
499878b19aaSToby Isaac 
5009566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(childSec, par, 1));
501878b19aaSToby Isaac   }
5029566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(childSec));
5039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(childSec, &cSize));
5049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cSize, &children));
5059566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(parMax - parMin, &offsets));
5069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd));
507878b19aaSToby Isaac   for (p = pStart; p < pEnd; p++) {
508878b19aaSToby Isaac     PetscInt dof, off, i;
509878b19aaSToby Isaac 
5109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec, p, &dof));
5119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(pSec, p, &off));
512878b19aaSToby Isaac     for (i = 0; i < dof; i++) {
513878b19aaSToby Isaac       PetscInt par = mesh->parents[off + i], cOff;
514878b19aaSToby Isaac 
5159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, par, &cOff));
516878b19aaSToby Isaac       children[cOff + offsets[par - parMin]++] = p;
517878b19aaSToby Isaac     }
518878b19aaSToby Isaac   }
519878b19aaSToby Isaac   mesh->childSection = childSec;
520878b19aaSToby Isaac   mesh->children     = children;
5219566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
5223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
523878b19aaSToby Isaac }
524878b19aaSToby Isaac 
AnchorsFlatten(PetscSection section,IS is,PetscSection * sectionNew,IS * isNew)525d71ae5a4SJacob Faibussowitsch static PetscErrorCode AnchorsFlatten(PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
526d71ae5a4SJacob Faibussowitsch {
5276dd5a8c8SToby Isaac   PetscInt        pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
5286dd5a8c8SToby Isaac   const PetscInt *vals;
5296dd5a8c8SToby Isaac   PetscSection    secNew;
5306dd5a8c8SToby Isaac   PetscBool       anyNew, globalAnyNew;
5316dd5a8c8SToby Isaac   PetscBool       compress;
5326dd5a8c8SToby Isaac 
5336dd5a8c8SToby Isaac   PetscFunctionBegin;
5349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
5359566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(is, &size));
5369566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(is, &vals));
5379566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secNew));
5389566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(secNew, pStart, pEnd));
5396dd5a8c8SToby Isaac   for (i = 0; i < size; i++) {
5406dd5a8c8SToby Isaac     PetscInt dof;
5416dd5a8c8SToby Isaac 
5426dd5a8c8SToby Isaac     p = vals[i];
5436dd5a8c8SToby Isaac     if (p < pStart || p >= pEnd) continue;
5449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
5456dd5a8c8SToby Isaac     if (dof) break;
5466dd5a8c8SToby Isaac   }
5476dd5a8c8SToby Isaac   if (i == size) {
5489566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5496dd5a8c8SToby Isaac     anyNew   = PETSC_FALSE;
5506dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5516dd5a8c8SToby Isaac     sizeNew  = 0;
5529371c9d4SSatish Balay   } else {
5536dd5a8c8SToby Isaac     anyNew = PETSC_TRUE;
5546dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5556dd5a8c8SToby Isaac       PetscInt dof, off;
5566dd5a8c8SToby Isaac 
5579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5596dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5606dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0;
5616dd5a8c8SToby Isaac 
56248a46eb9SPierre Jolivet         if (q >= pStart && q < pEnd) PetscCall(PetscSectionGetDof(section, q, &qDof));
5631baa6e33SBarry Smith         if (qDof) PetscCall(PetscSectionAddDof(secNew, p, qDof));
56448a46eb9SPierre Jolivet         else PetscCall(PetscSectionAddDof(secNew, p, 1));
5656dd5a8c8SToby Isaac       }
5666dd5a8c8SToby Isaac     }
5679566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(secNew));
5689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(secNew, &sizeNew));
5699566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sizeNew, &valsNew));
5706dd5a8c8SToby Isaac     compress = PETSC_FALSE;
5716dd5a8c8SToby Isaac     for (p = pStart; p < pEnd; p++) {
5726dd5a8c8SToby Isaac       PetscInt dof, off, count, offNew, dofNew;
5736dd5a8c8SToby Isaac 
5749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
5759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &off));
5769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(secNew, p, &dofNew));
5779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(secNew, p, &offNew));
5786dd5a8c8SToby Isaac       count = 0;
5796dd5a8c8SToby Isaac       for (i = 0; i < dof; i++) {
5806dd5a8c8SToby Isaac         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;
5816dd5a8c8SToby Isaac 
5826dd5a8c8SToby Isaac         if (q >= pStart && q < pEnd) {
5839566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, q, &qDof));
5849566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(section, q, &qOff));
5856dd5a8c8SToby Isaac         }
5866dd5a8c8SToby Isaac         if (qDof) {
5876dd5a8c8SToby Isaac           PetscInt oldCount = count;
5886dd5a8c8SToby Isaac 
5896dd5a8c8SToby Isaac           for (j = 0; j < qDof; j++) {
5906dd5a8c8SToby Isaac             PetscInt k, r = vals[qOff + j];
5916dd5a8c8SToby Isaac 
5926dd5a8c8SToby Isaac             for (k = 0; k < oldCount; k++) {
593ad540459SPierre Jolivet               if (valsNew[offNew + k] == r) break;
5946dd5a8c8SToby Isaac             }
595ad540459SPierre Jolivet             if (k == oldCount) valsNew[offNew + count++] = r;
5966dd5a8c8SToby Isaac           }
5979371c9d4SSatish Balay         } else {
5986dd5a8c8SToby Isaac           PetscInt k, oldCount = count;
5996dd5a8c8SToby Isaac 
6006dd5a8c8SToby Isaac           for (k = 0; k < oldCount; k++) {
601ad540459SPierre Jolivet             if (valsNew[offNew + k] == q) break;
6026dd5a8c8SToby Isaac           }
603ad540459SPierre Jolivet           if (k == oldCount) valsNew[offNew + count++] = q;
6046dd5a8c8SToby Isaac         }
6056dd5a8c8SToby Isaac       }
6066dd5a8c8SToby Isaac       if (count < dofNew) {
6079566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secNew, p, count));
6086dd5a8c8SToby Isaac         compress = PETSC_TRUE;
6096dd5a8c8SToby Isaac       }
6106dd5a8c8SToby Isaac     }
6116dd5a8c8SToby Isaac   }
6129566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(is, &vals));
613*5440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&anyNew, &globalAnyNew, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
6146dd5a8c8SToby Isaac   if (!globalAnyNew) {
6159566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secNew));
6166dd5a8c8SToby Isaac     *sectionNew = NULL;
6176dd5a8c8SToby Isaac     *isNew      = NULL;
6189371c9d4SSatish Balay   } else {
6196dd5a8c8SToby Isaac     if (compress) {
6206dd5a8c8SToby Isaac       PetscSection secComp;
6216dd5a8c8SToby Isaac       PetscInt    *valsComp = NULL;
6226dd5a8c8SToby Isaac 
6239566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secComp));
6249566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(secComp, pStart, pEnd));
6256dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6266dd5a8c8SToby Isaac         PetscInt dof;
6276dd5a8c8SToby Isaac 
6289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6299566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(secComp, p, dof));
6306dd5a8c8SToby Isaac       }
6319566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(secComp));
6329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(secComp, &sizeNew));
6339566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(sizeNew, &valsComp));
6346dd5a8c8SToby Isaac       for (p = pStart; p < pEnd; p++) {
6356dd5a8c8SToby Isaac         PetscInt dof, off, offNew, j;
6366dd5a8c8SToby Isaac 
6379566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(secNew, p, &dof));
6389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secNew, p, &off));
6399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(secComp, p, &offNew));
640ad540459SPierre Jolivet         for (j = 0; j < dof; j++) valsComp[offNew + j] = valsNew[off + j];
6416dd5a8c8SToby Isaac       }
6429566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&secNew));
6436dd5a8c8SToby Isaac       secNew = secComp;
6449566063dSJacob Faibussowitsch       PetscCall(PetscFree(valsNew));
6456dd5a8c8SToby Isaac       valsNew = valsComp;
6466dd5a8c8SToby Isaac     }
6479566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), sizeNew, valsNew, PETSC_OWN_POINTER, isNew));
6486dd5a8c8SToby Isaac   }
6493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6506dd5a8c8SToby Isaac }
6516dd5a8c8SToby Isaac 
DMPlexCreateAnchors_Tree(DM dm)652d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
653d71ae5a4SJacob Faibussowitsch {
65466af876cSToby Isaac   PetscInt     p, pStart, pEnd, *anchors, size;
6551690c2aeSBarry Smith   PetscInt     aMin = PETSC_INT_MAX, aMax = PETSC_INT_MIN;
65666af876cSToby Isaac   PetscSection aSec;
657f9f063d4SToby Isaac   DMLabel      canonLabel;
65866af876cSToby Isaac   IS           aIS;
65966af876cSToby Isaac 
66066af876cSToby Isaac   PetscFunctionBegin;
66166af876cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
6639566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "canonical", &canonLabel));
66466af876cSToby Isaac   for (p = pStart; p < pEnd; p++) {
66566af876cSToby Isaac     PetscInt parent;
66666af876cSToby Isaac 
667f9f063d4SToby Isaac     if (canonLabel) {
668f9f063d4SToby Isaac       PetscInt canon;
669f9f063d4SToby Isaac 
6709566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
671f9f063d4SToby Isaac       if (p != canon) continue;
672f9f063d4SToby Isaac     }
6739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
67466af876cSToby Isaac     if (parent != p) {
67566af876cSToby Isaac       aMin = PetscMin(aMin, p);
67666af876cSToby Isaac       aMax = PetscMax(aMax, p + 1);
67766af876cSToby Isaac     }
67866af876cSToby Isaac   }
67966af876cSToby Isaac   if (aMin > aMax) {
68066af876cSToby Isaac     aMin = -1;
68166af876cSToby Isaac     aMax = -1;
68266af876cSToby Isaac   }
6839566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &aSec));
6849566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(aSec, aMin, aMax));
68566af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
68666af876cSToby Isaac     PetscInt parent, ancestor = p;
68766af876cSToby Isaac 
688f9f063d4SToby Isaac     if (canonLabel) {
689f9f063d4SToby Isaac       PetscInt canon;
690f9f063d4SToby Isaac 
6919566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
692f9f063d4SToby Isaac       if (p != canon) continue;
693f9f063d4SToby Isaac     }
6949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
69566af876cSToby Isaac     while (parent != ancestor) {
69666af876cSToby Isaac       ancestor = parent;
6979566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
69866af876cSToby Isaac     }
69966af876cSToby Isaac     if (ancestor != p) {
70066af876cSToby Isaac       PetscInt closureSize, *closure = NULL;
70166af876cSToby Isaac 
7029566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
7039566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(aSec, p, closureSize));
7049566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
70566af876cSToby Isaac     }
70666af876cSToby Isaac   }
7079566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(aSec));
7089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(aSec, &size));
7099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &anchors));
71066af876cSToby Isaac   for (p = aMin; p < aMax; p++) {
71166af876cSToby Isaac     PetscInt parent, ancestor = p;
71266af876cSToby Isaac 
713f9f063d4SToby Isaac     if (canonLabel) {
714f9f063d4SToby Isaac       PetscInt canon;
715f9f063d4SToby Isaac 
7169566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
717f9f063d4SToby Isaac       if (p != canon) continue;
718f9f063d4SToby Isaac     }
7199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
72066af876cSToby Isaac     while (parent != ancestor) {
72166af876cSToby Isaac       ancestor = parent;
7229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
72366af876cSToby Isaac     }
72466af876cSToby Isaac     if (ancestor != p) {
72566af876cSToby Isaac       PetscInt j, closureSize, *closure = NULL, aOff;
72666af876cSToby Isaac 
7279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
72866af876cSToby Isaac 
7299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
730ad540459SPierre Jolivet       for (j = 0; j < closureSize; j++) anchors[aOff + j] = closure[2 * j];
7319566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
73266af876cSToby Isaac     }
73366af876cSToby Isaac   }
7349566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, anchors, PETSC_OWN_POINTER, &aIS));
7356dd5a8c8SToby Isaac   {
7366dd5a8c8SToby Isaac     PetscSection aSecNew = aSec;
7376dd5a8c8SToby Isaac     IS           aISNew  = aIS;
7386dd5a8c8SToby Isaac 
7399566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aSec));
7409566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)aIS));
7416dd5a8c8SToby Isaac     while (aSecNew) {
7429566063dSJacob Faibussowitsch       PetscCall(PetscSectionDestroy(&aSec));
7439566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&aIS));
7446dd5a8c8SToby Isaac       aSec    = aSecNew;
7456dd5a8c8SToby Isaac       aIS     = aISNew;
7466dd5a8c8SToby Isaac       aSecNew = NULL;
7476dd5a8c8SToby Isaac       aISNew  = NULL;
7489566063dSJacob Faibussowitsch       PetscCall(AnchorsFlatten(aSec, aIS, &aSecNew, &aISNew));
7496dd5a8c8SToby Isaac     }
7506dd5a8c8SToby Isaac   }
7519566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, aSec, aIS));
7529566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&aSec));
7539566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&aIS));
7543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
75566af876cSToby Isaac }
75666af876cSToby Isaac 
DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt * dof,PetscInt * numTrueSupp)757d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetTrueSupportSize(DM dm, PetscInt p, PetscInt *dof, PetscInt *numTrueSupp)
758d71ae5a4SJacob Faibussowitsch {
7596461c1adSToby Isaac   PetscFunctionBegin;
7606461c1adSToby Isaac   if (numTrueSupp[p] == -1) {
7616461c1adSToby Isaac     PetscInt        i, alldof;
7626461c1adSToby Isaac     const PetscInt *supp;
7636461c1adSToby Isaac     PetscInt        count = 0;
7646461c1adSToby Isaac 
7659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, p, &alldof));
7669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, p, &supp));
7676461c1adSToby Isaac     for (i = 0; i < alldof; i++) {
7686461c1adSToby Isaac       PetscInt        q = supp[i], numCones, j;
7696461c1adSToby Isaac       const PetscInt *cone;
7706461c1adSToby Isaac 
7719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, q, &numCones));
7729566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, q, &cone));
7736461c1adSToby Isaac       for (j = 0; j < numCones; j++) {
7746461c1adSToby Isaac         if (cone[j] == p) break;
7756461c1adSToby Isaac       }
7766461c1adSToby Isaac       if (j < numCones) count++;
7776461c1adSToby Isaac     }
7786461c1adSToby Isaac     numTrueSupp[p] = count;
7796461c1adSToby Isaac   }
7806461c1adSToby Isaac   *dof = numTrueSupp[p];
7813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7826461c1adSToby Isaac }
7836461c1adSToby Isaac 
DMPlexTreeExchangeSupports(DM dm)784d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
785d71ae5a4SJacob Faibussowitsch {
786776742edSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
787776742edSToby Isaac   PetscSection newSupportSection;
788776742edSToby Isaac   PetscInt     newSize, *newSupports, pStart, pEnd, p, d, depth;
7896461c1adSToby Isaac   PetscInt    *numTrueSupp;
790776742edSToby Isaac   PetscInt    *offsets;
791776742edSToby Isaac 
792776742edSToby Isaac   PetscFunctionBegin;
793776742edSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
794776742edSToby Isaac   /* symmetrize the hierarchy */
7959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
796f4f49eeaSPierre Jolivet   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)mesh->supportSection), &newSupportSection));
7979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7989566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSupportSection, pStart, pEnd));
7999566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd, &offsets));
8009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd, &numTrueSupp));
8016461c1adSToby Isaac   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
8026461c1adSToby Isaac   /* if a point is in the (true) support of q, it should be in the support of
803776742edSToby Isaac    * parent(q) */
804776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
806776742edSToby Isaac     for (p = pStart; p < pEnd; ++p) {
807776742edSToby Isaac       PetscInt dof, q, qdof, parent;
808776742edSToby Isaac 
8099566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTrueSupportSize(dm, p, &dof, numTrueSupp));
8109566063dSJacob Faibussowitsch       PetscCall(PetscSectionAddDof(newSupportSection, p, dof));
811776742edSToby Isaac       q = p;
8129566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
813776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
814776742edSToby Isaac         q = parent;
815776742edSToby Isaac 
8169566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTrueSupportSize(dm, q, &qdof, numTrueSupp));
8179566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, p, qdof));
8189566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(newSupportSection, q, dof));
8199566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
820776742edSToby Isaac       }
821776742edSToby Isaac     }
822776742edSToby Isaac   }
8239566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSupportSection));
8249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSupportSection, &newSize));
8259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(newSize, &newSupports));
826776742edSToby Isaac   for (d = 0; d <= depth; d++) {
8279566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
828776742edSToby Isaac     for (p = pStart; p < pEnd; p++) {
829776742edSToby Isaac       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;
830776742edSToby Isaac 
8319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
8329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
8339566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof));
8349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff));
835776742edSToby Isaac       for (i = 0; i < dof; i++) {
8366461c1adSToby Isaac         PetscInt        numCones, j;
8376461c1adSToby Isaac         const PetscInt *cone;
8386461c1adSToby Isaac         PetscInt        q = mesh->supports[off + i];
8396461c1adSToby Isaac 
8409566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, q, &numCones));
8419566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, q, &cone));
8426461c1adSToby Isaac         for (j = 0; j < numCones; j++) {
8436461c1adSToby Isaac           if (cone[j] == p) break;
8446461c1adSToby Isaac         }
8456461c1adSToby Isaac         if (j < numCones) newSupports[newOff + offsets[p]++] = q;
846776742edSToby Isaac       }
847776742edSToby Isaac 
848776742edSToby Isaac       q = p;
8499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
850776742edSToby Isaac       while (parent != q && parent >= pStart && parent < pEnd) {
851776742edSToby Isaac         q = parent;
8529566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof));
8539566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
8549566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff));
855776742edSToby Isaac         for (i = 0; i < qdof; i++) {
8566461c1adSToby Isaac           PetscInt        numCones, j;
8576461c1adSToby Isaac           const PetscInt *cone;
8586461c1adSToby Isaac           PetscInt        r = mesh->supports[qoff + i];
8596461c1adSToby Isaac 
8609566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
8619566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, r, &cone));
8626461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
8636461c1adSToby Isaac             if (cone[j] == q) break;
8646461c1adSToby Isaac           }
8656461c1adSToby Isaac           if (j < numCones) newSupports[newOff + offsets[p]++] = r;
866776742edSToby Isaac         }
867776742edSToby Isaac         for (i = 0; i < dof; i++) {
8686461c1adSToby Isaac           PetscInt        numCones, j;
8696461c1adSToby Isaac           const PetscInt *cone;
8706461c1adSToby Isaac           PetscInt        r = mesh->supports[off + i];
8716461c1adSToby Isaac 
8729566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
8739566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(dm, r, &cone));
8746461c1adSToby Isaac           for (j = 0; j < numCones; j++) {
8756461c1adSToby Isaac             if (cone[j] == p) break;
8766461c1adSToby Isaac           }
8776461c1adSToby Isaac           if (j < numCones) newSupports[newqOff + offsets[q]++] = r;
878776742edSToby Isaac         }
8799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
880776742edSToby Isaac       }
881776742edSToby Isaac     }
882776742edSToby Isaac   }
8839566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->supportSection));
884776742edSToby Isaac   mesh->supportSection = newSupportSection;
8859566063dSJacob Faibussowitsch   PetscCall(PetscFree(mesh->supports));
886776742edSToby Isaac   mesh->supports = newSupports;
8879566063dSJacob Faibussowitsch   PetscCall(PetscFree(offsets));
8889566063dSJacob Faibussowitsch   PetscCall(PetscFree(numTrueSupp));
8893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
890776742edSToby Isaac }
891776742edSToby Isaac 
892f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM, PetscSection, PetscSection, Mat);
893f7c74593SToby Isaac static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM, PetscSection, PetscSection, Mat);
894f7c74593SToby Isaac 
DMPlexSetTree_Internal(DM dm,PetscSection parentSection,PetscInt * parents,PetscInt * childIDs,PetscBool computeCanonical,PetscBool exchangeSupports)895d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
896d71ae5a4SJacob Faibussowitsch {
897f9f063d4SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
898f9f063d4SToby Isaac   DM       refTree;
899f9f063d4SToby Isaac   PetscInt size;
900f9f063d4SToby Isaac 
901f9f063d4SToby Isaac   PetscFunctionBegin;
902f9f063d4SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
903f9f063d4SToby Isaac   PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2);
9049566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)parentSection));
9059566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&mesh->parentSection));
906f9f063d4SToby Isaac   mesh->parentSection = parentSection;
9079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(parentSection, &size));
908f9f063d4SToby Isaac   if (parents != mesh->parents) {
9099566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->parents));
9109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->parents));
9119566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->parents, parents, size));
912f9f063d4SToby Isaac   }
913f9f063d4SToby Isaac   if (childIDs != mesh->childIDs) {
9149566063dSJacob Faibussowitsch     PetscCall(PetscFree(mesh->childIDs));
9159566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &mesh->childIDs));
9169566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size));
917f9f063d4SToby Isaac   }
9189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
919f9f063d4SToby Isaac   if (refTree) {
920f9f063d4SToby Isaac     DMLabel canonLabel;
921f9f063d4SToby Isaac 
9229566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(refTree, "canonical", &canonLabel));
923f9f063d4SToby Isaac     if (canonLabel) {
924f9f063d4SToby Isaac       PetscInt i;
925f9f063d4SToby Isaac 
926f9f063d4SToby Isaac       for (i = 0; i < size; i++) {
927f9f063d4SToby Isaac         PetscInt canon;
9289566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
929ad540459SPierre Jolivet         if (canon >= 0) mesh->childIDs[i] = canon;
930f9f063d4SToby Isaac       }
931f9f063d4SToby Isaac     }
932f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
9336e0288c8SStefano Zampini   } else {
934f7c74593SToby Isaac     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
935f9f063d4SToby Isaac   }
9369566063dSJacob Faibussowitsch   PetscCall(DMPlexTreeSymmetrize(dm));
937f9f063d4SToby Isaac   if (computeCanonical) {
938f9f063d4SToby Isaac     PetscInt d, dim;
939f9f063d4SToby Isaac 
940f9f063d4SToby Isaac     /* add the canonical label */
9419566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
9429566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(dm, "canonical"));
943f9f063d4SToby Isaac     for (d = 0; d <= dim; d++) {
944f9f063d4SToby Isaac       PetscInt        p, dStart, dEnd, canon = -1, cNumChildren;
945f9f063d4SToby Isaac       const PetscInt *cChildren;
946f9f063d4SToby Isaac 
9479566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
948f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
9499566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &cNumChildren, &cChildren));
950f9f063d4SToby Isaac         if (cNumChildren) {
951f9f063d4SToby Isaac           canon = p;
952f9f063d4SToby Isaac           break;
953f9f063d4SToby Isaac         }
954f9f063d4SToby Isaac       }
955f9f063d4SToby Isaac       if (canon == -1) continue;
956f9f063d4SToby Isaac       for (p = dStart; p < dEnd; p++) {
957f9f063d4SToby Isaac         PetscInt        numChildren, i;
958f9f063d4SToby Isaac         const PetscInt *children;
959f9f063d4SToby Isaac 
9609566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, p, &numChildren, &children));
961f9f063d4SToby Isaac         if (numChildren) {
96263a3b9bcSJacob 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);
9639566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "canonical", p, canon));
96448a46eb9SPierre Jolivet           for (i = 0; i < numChildren; i++) PetscCall(DMSetLabelValue(dm, "canonical", children[i], cChildren[i]));
965f9f063d4SToby Isaac         }
966f9f063d4SToby Isaac       }
967f9f063d4SToby Isaac     }
968f9f063d4SToby Isaac   }
9691baa6e33SBarry Smith   if (exchangeSupports) PetscCall(DMPlexTreeExchangeSupports(dm));
970f7c74593SToby Isaac   mesh->createanchors = DMPlexCreateAnchors_Tree;
971f7c74593SToby Isaac   /* reset anchors */
9729566063dSJacob Faibussowitsch   PetscCall(DMPlexSetAnchors(dm, NULL, NULL));
9733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
974f9f063d4SToby Isaac }
975f9f063d4SToby Isaac 
9760b7167a0SToby Isaac /*@
9770b7167a0SToby Isaac   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
978aaa8cc7dSPierre Jolivet   the point-to-point constraints determined by the tree: a point is constrained to the points in the closure of its
9790b7167a0SToby Isaac   tree root.
9800b7167a0SToby Isaac 
98120f4b53cSBarry Smith   Collective
9820b7167a0SToby Isaac 
9830b7167a0SToby Isaac   Input Parameters:
984a1cb98faSBarry Smith + dm            - the `DMPLEX` object
9850b7167a0SToby Isaac . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
9860b7167a0SToby Isaac                   offset indexes the parent and childID list; the reference count of parentSection is incremented
9870b7167a0SToby Isaac . parents       - a list of the point parents; copied, can be destroyed
9880b7167a0SToby Isaac - childIDs      - identifies the relationship of the child point to the parent point; if there is a reference tree, then
9890b7167a0SToby Isaac              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed
9900b7167a0SToby Isaac 
9910b7167a0SToby Isaac   Level: intermediate
9920b7167a0SToby Isaac 
9931cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
9940b7167a0SToby Isaac @*/
DMPlexSetTree(DM dm,PetscSection parentSection,PetscInt parents[],PetscInt childIDs[])995d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
996d71ae5a4SJacob Faibussowitsch {
9970b7167a0SToby Isaac   PetscFunctionBegin;
9989566063dSJacob Faibussowitsch   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_FALSE, PETSC_TRUE));
9993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10000b7167a0SToby Isaac }
10010b7167a0SToby Isaac 
1002b2f41788SToby Isaac /*@
1003b2f41788SToby Isaac   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
100420f4b53cSBarry Smith   Collective
1005b2f41788SToby Isaac 
1006f899ff85SJose E. Roman   Input Parameter:
1007a1cb98faSBarry Smith . dm - the `DMPLEX` object
1008b2f41788SToby Isaac 
1009b2f41788SToby Isaac   Output Parameters:
1010b2f41788SToby Isaac + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1011b2f41788SToby Isaac                   offset indexes the parent and childID list
1012b2f41788SToby Isaac . parents       - a list of the point parents
1013b2f41788SToby Isaac . childIDs      - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1014b2f41788SToby Isaac              the child corresponds to the point in the reference tree with index childID
1015b2f41788SToby Isaac . childSection  - the inverse of the parent section
1016b2f41788SToby Isaac - children      - a list of the point children
1017b2f41788SToby Isaac 
1018b2f41788SToby Isaac   Level: intermediate
1019b2f41788SToby Isaac 
10201cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`,`DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
1021b2f41788SToby Isaac @*/
DMPlexGetTree(DM dm,PetscSection * parentSection,PetscInt * parents[],PetscInt * childIDs[],PetscSection * childSection,PetscInt * children[])1022d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1023d71ae5a4SJacob Faibussowitsch {
1024b2f41788SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
1025b2f41788SToby Isaac 
1026b2f41788SToby Isaac   PetscFunctionBegin;
1027b2f41788SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1028b2f41788SToby Isaac   if (parentSection) *parentSection = mesh->parentSection;
1029b2f41788SToby Isaac   if (parents) *parents = mesh->parents;
1030b2f41788SToby Isaac   if (childIDs) *childIDs = mesh->childIDs;
1031b2f41788SToby Isaac   if (childSection) *childSection = mesh->childSection;
1032b2f41788SToby Isaac   if (children) *children = mesh->children;
10333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1034b2f41788SToby Isaac }
1035b2f41788SToby Isaac 
1036d961a43aSToby Isaac /*@
1037eaf898f9SPatrick Sanan   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)
1038d961a43aSToby Isaac 
1039d961a43aSToby Isaac   Input Parameters:
1040a1cb98faSBarry Smith + dm    - the `DMPLEX` object
1041d961a43aSToby Isaac - point - the query point
1042d961a43aSToby Isaac 
1043d961a43aSToby Isaac   Output Parameters:
104420f4b53cSBarry Smith + parent  - if not `NULL`, set to the parent of the point, or the point itself if the point does not have a parent
104520f4b53cSBarry Smith - childID - if not `NULL`, set to the child ID of the point with respect to its parent, or 0 if the point
1046d961a43aSToby Isaac             does not have a parent
1047d961a43aSToby Isaac 
1048d961a43aSToby Isaac   Level: intermediate
1049d961a43aSToby Isaac 
10501cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()`
1051d961a43aSToby Isaac @*/
DMPlexGetTreeParent(DM dm,PetscInt point,PetscInt * parent,PetscInt * childID)1052d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1053d71ae5a4SJacob Faibussowitsch {
1054d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1055d961a43aSToby Isaac   PetscSection pSec;
1056d961a43aSToby Isaac 
1057d961a43aSToby Isaac   PetscFunctionBegin;
1058d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1059d961a43aSToby Isaac   pSec = mesh->parentSection;
1060d961a43aSToby Isaac   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1061d961a43aSToby Isaac     PetscInt dof;
1062d961a43aSToby Isaac 
10639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pSec, point, &dof));
1064d961a43aSToby Isaac     if (dof) {
1065d961a43aSToby Isaac       PetscInt off;
1066d961a43aSToby Isaac 
10679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(pSec, point, &off));
1068d961a43aSToby Isaac       if (parent) *parent = mesh->parents[off];
1069d961a43aSToby Isaac       if (childID) *childID = mesh->childIDs[off];
10703ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
1071d961a43aSToby Isaac     }
1072d961a43aSToby Isaac   }
1073ad540459SPierre Jolivet   if (parent) *parent = point;
1074ad540459SPierre Jolivet   if (childID) *childID = 0;
10753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1076d961a43aSToby Isaac }
1077d961a43aSToby Isaac 
1078d961a43aSToby Isaac /*@C
1079eaf898f9SPatrick Sanan   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)
1080d961a43aSToby Isaac 
1081d961a43aSToby Isaac   Input Parameters:
1082a1cb98faSBarry Smith + dm    - the `DMPLEX` object
1083d961a43aSToby Isaac - point - the query point
1084d961a43aSToby Isaac 
1085d961a43aSToby Isaac   Output Parameters:
108620f4b53cSBarry Smith + numChildren - if not `NULL`, set to the number of children
108720f4b53cSBarry Smith - children    - if not `NULL`, set to a list children, or set to `NULL` if the point has no children
1088d961a43aSToby Isaac 
1089d961a43aSToby Isaac   Level: intermediate
1090d961a43aSToby Isaac 
10911cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()`
1092d961a43aSToby Isaac @*/
DMPlexGetTreeChildren(DM dm,PetscInt point,PetscInt * numChildren,const PetscInt * children[])1093d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1094d71ae5a4SJacob Faibussowitsch {
1095d961a43aSToby Isaac   DM_Plex     *mesh = (DM_Plex *)dm->data;
1096d961a43aSToby Isaac   PetscSection childSec;
1097d961a43aSToby Isaac   PetscInt     dof = 0;
1098d961a43aSToby Isaac 
1099d961a43aSToby Isaac   PetscFunctionBegin;
1100d961a43aSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1101d961a43aSToby Isaac   childSec = mesh->childSection;
110248a46eb9SPierre Jolivet   if (childSec && point >= childSec->pStart && point < childSec->pEnd) PetscCall(PetscSectionGetDof(childSec, point, &dof));
1103d961a43aSToby Isaac   if (numChildren) *numChildren = dof;
1104d961a43aSToby Isaac   if (children) {
1105d961a43aSToby Isaac     if (dof) {
1106d961a43aSToby Isaac       PetscInt off;
1107d961a43aSToby Isaac 
11089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(childSec, point, &off));
1109d961a43aSToby Isaac       *children = &mesh->children[off];
11109371c9d4SSatish Balay     } else {
1111d961a43aSToby Isaac       *children = NULL;
1112d961a43aSToby Isaac     }
1113d961a43aSToby Isaac   }
11143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1115d961a43aSToby Isaac }
11160c37af3bSToby Isaac 
EvaluateBasis(PetscSpace space,PetscInt nBasis,PetscInt nFunctionals,PetscInt nComps,PetscInt nPoints,const PetscInt * pointsPerFn,const PetscReal * points,const PetscReal * weights,PetscReal * work,Mat basisAtPoints)1117d71ae5a4SJacob Faibussowitsch 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)
1118d71ae5a4SJacob Faibussowitsch {
111952a3aeb4SToby Isaac   PetscInt f, b, p, c, offset, qPoints;
1120b3a4bf2aSToby Isaac 
1121b3a4bf2aSToby Isaac   PetscFunctionBegin;
11229566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(space, nPoints, points, work, NULL, NULL));
112352a3aeb4SToby Isaac   for (f = 0, offset = 0; f < nFunctionals; f++) {
112452a3aeb4SToby Isaac     qPoints = pointsPerFn[f];
112552a3aeb4SToby Isaac     for (b = 0; b < nBasis; b++) {
1126b3a4bf2aSToby Isaac       PetscScalar val = 0.;
1127b3a4bf2aSToby Isaac 
112852a3aeb4SToby Isaac       for (p = 0; p < qPoints; p++) {
1129ad540459SPierre Jolivet         for (c = 0; c < nComps; c++) val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
113052a3aeb4SToby Isaac       }
11319566063dSJacob Faibussowitsch       PetscCall(MatSetValue(basisAtPoints, b, f, val, INSERT_VALUES));
1132b3a4bf2aSToby Isaac     }
1133b3a4bf2aSToby Isaac     offset += qPoints;
1134b3a4bf2aSToby Isaac   }
11359566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(basisAtPoints, MAT_FINAL_ASSEMBLY));
11369566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(basisAtPoints, MAT_FINAL_ASSEMBLY));
11373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1138b3a4bf2aSToby Isaac }
1139b3a4bf2aSToby Isaac 
DMPlexComputeAnchorMatrix_Tree_Direct(DM dm,PetscSection section,PetscSection cSec,Mat cMat)1140d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
1141d71ae5a4SJacob Faibussowitsch {
11420c37af3bSToby Isaac   PetscDS         ds;
11430c37af3bSToby Isaac   PetscInt        spdim;
11440c37af3bSToby Isaac   PetscInt        numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
11450c37af3bSToby Isaac   const PetscInt *anchors;
1146f7c74593SToby Isaac   PetscSection    aSec;
11470c37af3bSToby Isaac   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
11480c37af3bSToby Isaac   IS              aIS;
11490c37af3bSToby Isaac 
11500c37af3bSToby Isaac   PetscFunctionBegin;
11519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
11529566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
11539566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
11549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
11559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
11569566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
11579566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &conStart, &conEnd));
11589566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &spdim));
11599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(spdim, &v0, spdim, &v0parent, spdim, &vtmp, spdim * spdim, &J, spdim * spdim, &Jparent, spdim * spdim, &invJparent));
11600c37af3bSToby Isaac 
11610c37af3bSToby Isaac   for (f = 0; f < numFields; f++) {
11620dd1b1feSToby Isaac     PetscObject          disc;
11630dd1b1feSToby Isaac     PetscClassId         id;
1164b3a4bf2aSToby Isaac     PetscSpace           bspace;
1165b3a4bf2aSToby Isaac     PetscDualSpace       dspace;
11669c3cf19fSMatthew G. Knepley     PetscInt             i, j, k, nPoints, Nc, offset;
116752a3aeb4SToby Isaac     PetscInt             fSize, maxDof;
1168b3a4bf2aSToby Isaac     PetscReal           *weights, *pointsRef, *pointsReal, *work;
11691683a169SBarry Smith     PetscScalar         *scwork;
11701683a169SBarry Smith     const PetscScalar   *X;
11712c44ad04SToby Isaac     PetscInt            *sizes, *workIndRow, *workIndCol;
11720c37af3bSToby Isaac     Mat                  Amat, Bmat, Xmat;
11732c44ad04SToby Isaac     const PetscInt      *numDof = NULL;
1174085f0adfSToby Isaac     const PetscInt    ***perms  = NULL;
1175085f0adfSToby Isaac     const PetscScalar ***flips  = NULL;
11760c37af3bSToby Isaac 
11779566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds, f, &disc));
11789566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc, &id));
11790dd1b1feSToby Isaac     if (id == PETSCFE_CLASSID) {
1180b3a4bf2aSToby Isaac       PetscFE fe = (PetscFE)disc;
1181b3a4bf2aSToby Isaac 
11829566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe, &bspace));
11839566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(fe, &dspace));
11849566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11859566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
11869371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
1187b3a4bf2aSToby Isaac       PetscFV fv = (PetscFV)disc;
1188b3a4bf2aSToby Isaac 
11899566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
11909566063dSJacob Faibussowitsch       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv), &bspace));
11919566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetType(bspace, PETSCSPACEPOLYNOMIAL));
11929566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetDegree(bspace, 0, PETSC_DETERMINE));
11939566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumComponents(bspace, Nc));
11949566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetNumVariables(bspace, spdim));
11959566063dSJacob Faibussowitsch       PetscCall(PetscSpaceSetUp(bspace));
11969566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &dspace));
11979566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
11989371c9d4SSatish Balay     } else SETERRQ(PetscObjectComm(disc), PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
11999566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetNumDof(dspace, &numDof));
1200ad540459SPierre Jolivet     for (i = 0, maxDof = 0; i <= spdim; i++) maxDof = PetscMax(maxDof, numDof[i]);
12019566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSymmetries(dspace, &perms, &flips));
12020dd1b1feSToby Isaac 
12039566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &Amat));
12049566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(Amat, fSize, fSize, fSize, fSize));
12059566063dSJacob Faibussowitsch     PetscCall(MatSetType(Amat, MATSEQDENSE));
12069566063dSJacob Faibussowitsch     PetscCall(MatSetUp(Amat));
12079566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Bmat));
12089566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Xmat));
12090c37af3bSToby Isaac     nPoints = 0;
12100c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
121152a3aeb4SToby Isaac       PetscInt        qPoints, thisNc;
12120c37af3bSToby Isaac       PetscQuadrature quad;
12130c37af3bSToby Isaac 
12149566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12159566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, &thisNc, &qPoints, NULL, NULL));
121663a3b9bcSJacob Faibussowitsch       PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
12170c37af3bSToby Isaac       nPoints += qPoints;
12180c37af3bSToby Isaac     }
12199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(fSize, &sizes, nPoints * Nc, &weights, spdim * nPoints, &pointsRef, spdim * nPoints, &pointsReal, nPoints * fSize * Nc, &work, maxDof, &workIndRow, maxDof, &workIndCol));
12209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof * maxDof, &scwork));
12210c37af3bSToby Isaac     offset = 0;
12220c37af3bSToby Isaac     for (i = 0; i < fSize; i++) {
12230c37af3bSToby Isaac       PetscInt         qPoints;
12240c37af3bSToby Isaac       const PetscReal *p, *w;
12250c37af3bSToby Isaac       PetscQuadrature  quad;
12260c37af3bSToby Isaac 
12279566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
12289566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &qPoints, &p, &w));
12299566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(weights + Nc * offset, w, Nc * qPoints));
12309566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pointsRef + spdim * offset, p, spdim * qPoints));
1231b3a4bf2aSToby Isaac       sizes[i] = qPoints;
12320c37af3bSToby Isaac       offset += qPoints;
12330c37af3bSToby Isaac     }
12349566063dSJacob Faibussowitsch     PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsRef, weights, work, Amat));
12359566063dSJacob Faibussowitsch     PetscCall(MatLUFactor(Amat, NULL, NULL, NULL));
12360c37af3bSToby Isaac     for (c = cStart; c < cEnd; c++) {
12370c37af3bSToby Isaac       PetscInt  parent;
12380c37af3bSToby Isaac       PetscInt  closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
12390c37af3bSToby Isaac       PetscInt *childOffsets, *parentOffsets;
12400c37af3bSToby Isaac 
12419566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, c, &parent, NULL));
12420c37af3bSToby Isaac       if (parent == c) continue;
12439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12440c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12450c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12460c37af3bSToby Isaac         PetscInt conDof;
12470c37af3bSToby Isaac 
12480c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1249085f0adfSToby Isaac         if (numFields) {
12509566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
12519371c9d4SSatish Balay         } else {
12529566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
12530c37af3bSToby Isaac         }
12540c37af3bSToby Isaac         if (conDof) break;
12550c37af3bSToby Isaac       }
12560c37af3bSToby Isaac       if (i == closureSize) {
12579566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
12580c37af3bSToby Isaac         continue;
12590c37af3bSToby Isaac       }
12600c37af3bSToby Isaac 
12619566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
12629566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
12630c37af3bSToby Isaac       for (i = 0; i < nPoints; i++) {
1264c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
1265c330f8ffSToby Isaac 
1266c330f8ffSToby Isaac         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i * spdim], vtmp);
1267c330f8ffSToby Isaac         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i * spdim]);
12680c37af3bSToby Isaac       }
12699566063dSJacob Faibussowitsch       PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsReal, weights, work, Bmat));
12709566063dSJacob Faibussowitsch       PetscCall(MatMatSolve(Amat, Bmat, Xmat));
12719566063dSJacob Faibussowitsch       PetscCall(MatDenseGetArrayRead(Xmat, &X));
12729566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
12739566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(closureSize + 1, &childOffsets, closureSizeP + 1, &parentOffsets));
12740c37af3bSToby Isaac       childOffsets[0] = 0;
12750c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12760c37af3bSToby Isaac         PetscInt p = closure[2 * i];
12770c37af3bSToby Isaac         PetscInt dof;
12780c37af3bSToby Isaac 
1279085f0adfSToby Isaac         if (numFields) {
12809566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12819371c9d4SSatish Balay         } else {
12829566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12830c37af3bSToby Isaac         }
128452a3aeb4SToby Isaac         childOffsets[i + 1] = childOffsets[i] + dof;
12850c37af3bSToby Isaac       }
12860c37af3bSToby Isaac       parentOffsets[0] = 0;
12870c37af3bSToby Isaac       for (i = 0; i < closureSizeP; i++) {
12880c37af3bSToby Isaac         PetscInt p = closureP[2 * i];
12890c37af3bSToby Isaac         PetscInt dof;
12900c37af3bSToby Isaac 
1291085f0adfSToby Isaac         if (numFields) {
12929566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
12939371c9d4SSatish Balay         } else {
12949566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(section, p, &dof));
12950c37af3bSToby Isaac         }
129652a3aeb4SToby Isaac         parentOffsets[i + 1] = parentOffsets[i] + dof;
12970c37af3bSToby Isaac       }
12980c37af3bSToby Isaac       for (i = 0; i < closureSize; i++) {
12992c44ad04SToby Isaac         PetscInt           conDof, conOff, aDof, aOff, nWork;
13000c37af3bSToby Isaac         PetscInt           p = closure[2 * i];
13010c37af3bSToby Isaac         PetscInt           o = closure[2 * i + 1];
1302085f0adfSToby Isaac         const PetscInt    *perm;
1303085f0adfSToby Isaac         const PetscScalar *flip;
13040c37af3bSToby Isaac 
13050c37af3bSToby Isaac         if (p < conStart || p >= conEnd) continue;
1306085f0adfSToby Isaac         if (numFields) {
13079566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
13089566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &conOff));
13099371c9d4SSatish Balay         } else {
13109566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
13119566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cSec, p, &conOff));
13120c37af3bSToby Isaac         }
13130c37af3bSToby Isaac         if (!conDof) continue;
1314085f0adfSToby Isaac         perm = (perms && perms[i]) ? perms[i][o] : NULL;
1315085f0adfSToby Isaac         flip = (flips && flips[i]) ? flips[i][o] : NULL;
13169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
13179566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
13182c44ad04SToby Isaac         nWork = childOffsets[i + 1] - childOffsets[i];
13190c37af3bSToby Isaac         for (k = 0; k < aDof; k++) {
13200c37af3bSToby Isaac           PetscInt a = anchors[aOff + k];
13210c37af3bSToby Isaac           PetscInt aSecDof, aSecOff;
13220c37af3bSToby Isaac 
1323085f0adfSToby Isaac           if (numFields) {
13249566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, a, f, &aSecDof));
13259566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aSecOff));
13269371c9d4SSatish Balay           } else {
13279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, a, &aSecDof));
13289566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, a, &aSecOff));
13290c37af3bSToby Isaac           }
13300c37af3bSToby Isaac           if (!aSecDof) continue;
13310c37af3bSToby Isaac 
13320c37af3bSToby Isaac           for (j = 0; j < closureSizeP; j++) {
13330c37af3bSToby Isaac             PetscInt q  = closureP[2 * j];
13340c37af3bSToby Isaac             PetscInt oq = closureP[2 * j + 1];
13352c44ad04SToby Isaac 
13362c44ad04SToby Isaac             if (q == a) {
133752a3aeb4SToby Isaac               PetscInt           r, s, nWorkP;
1338085f0adfSToby Isaac               const PetscInt    *permP;
1339085f0adfSToby Isaac               const PetscScalar *flipP;
1340085f0adfSToby Isaac 
1341085f0adfSToby Isaac               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1342085f0adfSToby Isaac               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
13432c44ad04SToby Isaac               nWorkP = parentOffsets[j + 1] - parentOffsets[j];
13442c44ad04SToby Isaac               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
13451683a169SBarry Smith                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
13462c44ad04SToby Isaac                * column-major, so transpose-transpose = do nothing */
13472c44ad04SToby Isaac               for (r = 0; r < nWork; r++) {
1348ad540459SPierre Jolivet                 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
13492c44ad04SToby Isaac               }
1350ad540459SPierre Jolivet               for (r = 0; r < nWork; r++) workIndRow[perm ? perm[r] : r] = conOff + r;
1351ad540459SPierre Jolivet               for (s = 0; s < nWorkP; s++) workIndCol[permP ? permP[s] : s] = aSecOff + s;
13522c44ad04SToby Isaac               if (flip) {
13532c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1354ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flip[r];
13552c44ad04SToby Isaac                 }
13562c44ad04SToby Isaac               }
13572c44ad04SToby Isaac               if (flipP) {
13582c44ad04SToby Isaac                 for (r = 0; r < nWork; r++) {
1359ad540459SPierre Jolivet                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flipP[s];
13602c44ad04SToby Isaac                 }
13612c44ad04SToby Isaac               }
13629566063dSJacob Faibussowitsch               PetscCall(MatSetValues(cMat, nWork, workIndRow, nWorkP, workIndCol, scwork, INSERT_VALUES));
13632c44ad04SToby Isaac               break;
13640c37af3bSToby Isaac             }
13650c37af3bSToby Isaac           }
13660c37af3bSToby Isaac         }
13670c37af3bSToby Isaac       }
13689566063dSJacob Faibussowitsch       PetscCall(MatDenseRestoreArrayRead(Xmat, &X));
13699566063dSJacob Faibussowitsch       PetscCall(PetscFree2(childOffsets, parentOffsets));
13709566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
13719566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
13720c37af3bSToby Isaac     }
13739566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Amat));
13749566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Bmat));
13759566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Xmat));
13769566063dSJacob Faibussowitsch     PetscCall(PetscFree(scwork));
13779566063dSJacob Faibussowitsch     PetscCall(PetscFree7(sizes, weights, pointsRef, pointsReal, work, workIndRow, workIndCol));
137848a46eb9SPierre Jolivet     if (id == PETSCFV_CLASSID) PetscCall(PetscSpaceDestroy(&bspace));
13790c37af3bSToby Isaac   }
13809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
13819566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
13829566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJparent));
13839566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
13843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13850c37af3bSToby Isaac }
138695a0b26dSToby Isaac 
DMPlexReferenceTreeGetChildrenMatrices(DM refTree,PetscScalar **** childrenMats,PetscInt *** childrenN)1387d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1388d71ae5a4SJacob Faibussowitsch {
1389f7c74593SToby Isaac   Mat                 refCmat;
139021968bf8SToby Isaac   PetscDS             ds;
1391085f0adfSToby Isaac   PetscInt            numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
139221968bf8SToby Isaac   PetscScalar      ***refPointFieldMats;
139321968bf8SToby Isaac   PetscSection        refConSec, refAnSec, refSection;
139421968bf8SToby Isaac   IS                  refAnIS;
139521968bf8SToby Isaac   const PetscInt     *refAnchors;
1396085f0adfSToby Isaac   const PetscInt    **perms;
1397085f0adfSToby Isaac   const PetscScalar **flips;
139895a0b26dSToby Isaac 
139995a0b26dSToby Isaac   PetscFunctionBegin;
14009566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
14019566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1402085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
14039566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
14049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
14059566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(refAnIS, &refAnchors));
14069566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
14079566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
14089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
14099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldN));
14109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
14119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
14129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
14139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxAnDof, &cols));
141495a0b26dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
141595a0b26dSToby Isaac     PetscInt parent, closureSize, *closure = NULL, pDof;
141695a0b26dSToby Isaac 
14179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
14189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
141995a0b26dSToby Isaac     if (!pDof || parent == p) continue;
142095a0b26dSToby Isaac 
14219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxFields, &refPointFieldMats[p - pRefStart]));
14229566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxFields, &refPointFieldN[p - pRefStart]));
14239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1424085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
1425085f0adfSToby Isaac       PetscInt cDof, cOff, numCols, r, i;
142695a0b26dSToby Isaac 
1427085f0adfSToby Isaac       if (f < numFields) {
14289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
14299566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
14309566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1431085f0adfSToby Isaac       } else {
14329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
14339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
14349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetPointSyms(refSection, closureSize, closure, &perms, &flips));
143595a0b26dSToby Isaac       }
143695a0b26dSToby Isaac 
1437ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
143895a0b26dSToby Isaac       numCols = 0;
143995a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
144095a0b26dSToby Isaac         PetscInt        q = closure[2 * i];
144195a0b26dSToby Isaac         PetscInt        aDof, aOff, j;
1442085f0adfSToby Isaac         const PetscInt *perm = perms ? perms[i] : NULL;
144395a0b26dSToby Isaac 
1444085f0adfSToby Isaac         if (numFields) {
14459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14469566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14479371c9d4SSatish Balay         } else {
14489566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14499566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
145095a0b26dSToby Isaac         }
145195a0b26dSToby Isaac 
1452ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + (perm ? perm[j] : j);
145395a0b26dSToby Isaac       }
145495a0b26dSToby Isaac       refPointFieldN[p - pRefStart][f] = numCols;
14559566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
14569566063dSJacob Faibussowitsch       PetscCall(MatGetValues(refCmat, cDof, rows, numCols, cols, refPointFieldMats[p - pRefStart][f]));
1457085f0adfSToby Isaac       if (flips) {
1458085f0adfSToby Isaac         PetscInt colOff = 0;
1459085f0adfSToby Isaac 
1460085f0adfSToby Isaac         for (i = 0; i < closureSize; i++) {
1461085f0adfSToby Isaac           PetscInt           q = closure[2 * i];
1462085f0adfSToby Isaac           PetscInt           aDof, aOff, j;
1463085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
1464085f0adfSToby Isaac 
1465085f0adfSToby Isaac           if (numFields) {
14669566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
14679566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
14689371c9d4SSatish Balay           } else {
14699566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(refSection, q, &aDof));
14709566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1471085f0adfSToby Isaac           }
1472085f0adfSToby Isaac           if (flip) {
1473085f0adfSToby Isaac             PetscInt k;
1474085f0adfSToby Isaac             for (k = 0; k < cDof; k++) {
1475ad540459SPierre Jolivet               for (j = 0; j < aDof; j++) refPointFieldMats[p - pRefStart][f][k * numCols + colOff + j] *= flip[j];
1476085f0adfSToby Isaac             }
1477085f0adfSToby Isaac           }
1478085f0adfSToby Isaac           colOff += aDof;
1479085f0adfSToby Isaac         }
1480085f0adfSToby Isaac       }
1481085f0adfSToby Isaac       if (numFields) {
14829566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestoreFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1483085f0adfSToby Isaac       } else {
14849566063dSJacob Faibussowitsch         PetscCall(PetscSectionRestorePointSyms(refSection, closureSize, closure, &perms, &flips));
1485085f0adfSToby Isaac       }
148695a0b26dSToby Isaac     }
14879566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
148895a0b26dSToby Isaac   }
148921968bf8SToby Isaac   *childrenMats = refPointFieldMats;
149021968bf8SToby Isaac   *childrenN    = refPointFieldN;
14919566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(refAnIS, &refAnchors));
14929566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
14939566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
14943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
149521968bf8SToby Isaac }
149621968bf8SToby Isaac 
DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree,PetscScalar **** childrenMats,PetscInt *** childrenN)1497d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1498d71ae5a4SJacob Faibussowitsch {
149921968bf8SToby Isaac   PetscDS        ds;
150021968bf8SToby Isaac   PetscInt     **refPointFieldN;
150121968bf8SToby Isaac   PetscScalar ***refPointFieldMats;
1502085f0adfSToby Isaac   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
150321968bf8SToby Isaac   PetscSection   refConSec;
150421968bf8SToby Isaac 
150521968bf8SToby Isaac   PetscFunctionBegin;
150621968bf8SToby Isaac   refPointFieldN    = *childrenN;
150721968bf8SToby Isaac   *childrenN        = NULL;
150821968bf8SToby Isaac   refPointFieldMats = *childrenMats;
150921968bf8SToby Isaac   *childrenMats     = NULL;
15109566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
15119566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1512367003a6SStefano Zampini   maxFields = PetscMax(1, numFields);
15139566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
15149566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
151521968bf8SToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
151621968bf8SToby Isaac     PetscInt parent, pDof;
151721968bf8SToby Isaac 
15189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
15199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
152021968bf8SToby Isaac     if (!pDof || parent == p) continue;
152121968bf8SToby Isaac 
1522085f0adfSToby Isaac     for (f = 0; f < maxFields; f++) {
152321968bf8SToby Isaac       PetscInt cDof;
152421968bf8SToby Isaac 
1525085f0adfSToby Isaac       if (numFields) {
15269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
15279371c9d4SSatish Balay       } else {
15289566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
152921968bf8SToby Isaac       }
153021968bf8SToby Isaac 
15319566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
153221968bf8SToby Isaac     }
15339566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
15349566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
153521968bf8SToby Isaac   }
15369566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
15379566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldN));
15383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153921968bf8SToby Isaac }
154021968bf8SToby Isaac 
DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm,PetscSection section,PetscSection conSec,Mat cMat)1541d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
1542d71ae5a4SJacob Faibussowitsch {
154321968bf8SToby Isaac   DM              refTree;
154421968bf8SToby Isaac   PetscDS         ds;
154521968bf8SToby Isaac   Mat             refCmat;
1546085f0adfSToby Isaac   PetscInt        numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
154721968bf8SToby Isaac   PetscScalar  ***refPointFieldMats, *pointWork;
154821968bf8SToby Isaac   PetscSection    refConSec, refAnSec, anSec;
154921968bf8SToby Isaac   IS              refAnIS, anIS;
155021968bf8SToby Isaac   const PetscInt *anchors;
155121968bf8SToby Isaac 
155221968bf8SToby Isaac   PetscFunctionBegin;
155321968bf8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
15549566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &ds));
15559566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
1556085f0adfSToby Isaac   maxFields = PetscMax(1, numFields);
15579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
15589566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, refTree));
1559c77c71ffSToby Isaac   PetscCall(DMSetLocalSection(refTree, NULL));
1560c77c71ffSToby Isaac   PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
15619566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
15629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
15639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS));
15649566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(anIS, &anchors));
15659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
15669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd));
15679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
15689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
15699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork));
157021968bf8SToby Isaac 
157121968bf8SToby Isaac   /* step 1: get submats for every constrained point in the reference tree */
15729566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
157395a0b26dSToby Isaac 
157495a0b26dSToby Isaac   /* step 2: compute the preorder */
15759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
15769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm));
157795a0b26dSToby Isaac   for (p = pStart; p < pEnd; p++) {
157895a0b26dSToby Isaac     perm[p - pStart]  = p;
157995a0b26dSToby Isaac     iperm[p - pStart] = p - pStart;
158095a0b26dSToby Isaac   }
158195a0b26dSToby Isaac   for (p = 0; p < pEnd - pStart;) {
158295a0b26dSToby Isaac     PetscInt point = perm[p];
158395a0b26dSToby Isaac     PetscInt parent;
158495a0b26dSToby Isaac 
15859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
158695a0b26dSToby Isaac     if (parent == point) {
158795a0b26dSToby Isaac       p++;
15889371c9d4SSatish Balay     } else {
158995a0b26dSToby Isaac       PetscInt size, closureSize, *closure = NULL, i;
159095a0b26dSToby Isaac 
15919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
159295a0b26dSToby Isaac       for (i = 0; i < closureSize; i++) {
159395a0b26dSToby Isaac         PetscInt q = closure[2 * i];
159495a0b26dSToby Isaac         if (iperm[q - pStart] > iperm[point - pStart]) {
159595a0b26dSToby Isaac           /* swap */
159695a0b26dSToby Isaac           perm[p]                 = q;
159795a0b26dSToby Isaac           perm[iperm[q - pStart]] = point;
159895a0b26dSToby Isaac           iperm[point - pStart]   = iperm[q - pStart];
159995a0b26dSToby Isaac           iperm[q - pStart]       = p;
160095a0b26dSToby Isaac           break;
160195a0b26dSToby Isaac         }
160295a0b26dSToby Isaac       }
160395a0b26dSToby Isaac       size = closureSize;
16049566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1605ad540459SPierre Jolivet       if (i == size) p++;
160695a0b26dSToby Isaac     }
160795a0b26dSToby Isaac   }
160895a0b26dSToby Isaac 
160995a0b26dSToby Isaac   /* step 3: fill the constraint matrix */
161095a0b26dSToby Isaac   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
161195a0b26dSToby Isaac    * allow progressive fill without assembly, so we are going to set up the
161295a0b26dSToby Isaac    * values outside of the Mat first.
161395a0b26dSToby Isaac    */
161495a0b26dSToby Isaac   {
161595a0b26dSToby Isaac     PetscInt        nRows, row, nnz;
161695a0b26dSToby Isaac     PetscBool       done;
1617cd6fc93eSToby Isaac     PetscInt        secStart, secEnd;
161895a0b26dSToby Isaac     const PetscInt *ia, *ja;
161995a0b26dSToby Isaac     PetscScalar    *vals;
162095a0b26dSToby Isaac 
1621cd6fc93eSToby Isaac     PetscCall(PetscSectionGetChart(section, &secStart, &secEnd));
16229566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
162328b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix");
162495a0b26dSToby Isaac     nnz = ia[nRows];
162595a0b26dSToby Isaac     /* malloc and then zero rows right before we fill them: this way valgrind
162695a0b26dSToby Isaac      * can tell if we are doing progressive fill in the wrong order */
16279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vals));
162895a0b26dSToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
162995a0b26dSToby Isaac       PetscInt parent, childid, closureSize, *closure = NULL;
163095a0b26dSToby Isaac       PetscInt point = perm[p], pointDof;
163195a0b26dSToby Isaac 
16329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid));
163395a0b26dSToby Isaac       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
16349566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(conSec, point, &pointDof));
163595a0b26dSToby Isaac       if (!pointDof) continue;
16369566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1637085f0adfSToby Isaac       for (f = 0; f < maxFields; f++) {
1638085f0adfSToby Isaac         PetscInt            cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
163995a0b26dSToby Isaac         PetscScalar        *pointMat;
1640085f0adfSToby Isaac         const PetscInt    **perms;
1641085f0adfSToby Isaac         const PetscScalar **flips;
164295a0b26dSToby Isaac 
1643085f0adfSToby Isaac         if (numFields) {
16449566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof));
16459566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff));
16469371c9d4SSatish Balay         } else {
16479566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(conSec, point, &cDof));
16489566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(conSec, point, &cOff));
164995a0b26dSToby Isaac         }
165095a0b26dSToby Isaac         if (!cDof) continue;
16519566063dSJacob Faibussowitsch         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
16529566063dSJacob Faibussowitsch         else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips));
165395a0b26dSToby Isaac 
165495a0b26dSToby Isaac         /* make sure that every row for this point is the same size */
165576bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
165695a0b26dSToby Isaac           for (r = 0; r < cDof; r++) {
165795a0b26dSToby Isaac             if (cDof > 1 && r) {
165857508eceSPierre Jolivet               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]);
165995a0b26dSToby Isaac             }
166095a0b26dSToby Isaac           }
166176bd3646SJed Brown         }
166295a0b26dSToby Isaac         /* zero rows */
1663ad540459SPierre Jolivet         for (i = ia[cOff]; i < ia[cOff + cDof]; i++) vals[i] = 0.;
166495a0b26dSToby Isaac         matOffset   = ia[cOff];
166595a0b26dSToby Isaac         numFillCols = ia[cOff + 1] - matOffset;
166695a0b26dSToby Isaac         pointMat    = refPointFieldMats[childid - pRefStart][f];
166795a0b26dSToby Isaac         numCols     = refPointFieldN[childid - pRefStart][f];
166895a0b26dSToby Isaac         offset      = 0;
166995a0b26dSToby Isaac         for (i = 0; i < closureSize; i++) {
167095a0b26dSToby Isaac           PetscInt           q = closure[2 * i];
167195a0b26dSToby Isaac           PetscInt           aDof, aOff, j, k, qConDof, qConOff;
1672085f0adfSToby Isaac           const PetscInt    *perm = perms ? perms[i] : NULL;
1673085f0adfSToby Isaac           const PetscScalar *flip = flips ? flips[i] : NULL;
167495a0b26dSToby Isaac 
167595a0b26dSToby Isaac           qConDof = qConOff = 0;
1676cd6fc93eSToby Isaac           if (q < secStart || q >= secEnd) continue;
1677085f0adfSToby Isaac           if (numFields) {
16789566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof));
16799566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff));
168095a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16819566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof));
16829566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff));
168395a0b26dSToby Isaac             }
16849371c9d4SSatish Balay           } else {
16859566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, q, &aDof));
16869566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(section, q, &aOff));
168795a0b26dSToby Isaac             if (q >= conStart && q < conEnd) {
16889566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetDof(conSec, q, &qConDof));
16899566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(conSec, q, &qConOff));
169095a0b26dSToby Isaac             }
169195a0b26dSToby Isaac           }
169295a0b26dSToby Isaac           if (!aDof) continue;
169395a0b26dSToby Isaac           if (qConDof) {
169495a0b26dSToby Isaac             /* this point has anchors: its rows of the matrix should already
169595a0b26dSToby Isaac              * be filled, thanks to preordering */
169695a0b26dSToby Isaac             /* first multiply into pointWork, then set in matrix */
169795a0b26dSToby Isaac             PetscInt aMatOffset   = ia[qConOff];
169895a0b26dSToby Isaac             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
169995a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
170095a0b26dSToby Isaac               for (j = 0; j < aNumFillCols; j++) {
170195a0b26dSToby Isaac                 PetscScalar inVal = 0;
170295a0b26dSToby Isaac                 for (k = 0; k < aDof; k++) {
1703085f0adfSToby Isaac                   PetscInt col = perm ? perm[k] : k;
170495a0b26dSToby Isaac 
1705085f0adfSToby Isaac                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
170695a0b26dSToby Isaac                 }
170795a0b26dSToby Isaac                 pointWork[r * aNumFillCols + j] = inVal;
170895a0b26dSToby Isaac               }
170995a0b26dSToby Isaac             }
171095a0b26dSToby Isaac             /* assume that the columns are sorted, spend less time searching */
171195a0b26dSToby Isaac             for (j = 0, k = 0; j < aNumFillCols; j++) {
171295a0b26dSToby Isaac               PetscInt col = ja[aMatOffset + j];
171395a0b26dSToby Isaac               for (; k < numFillCols; k++) {
1714ad540459SPierre Jolivet                 if (ja[matOffset + k] == col) break;
171595a0b26dSToby Isaac               }
171663a3b9bcSJacob Faibussowitsch               PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
1717ad540459SPierre Jolivet               for (r = 0; r < cDof; r++) vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
171895a0b26dSToby Isaac             }
17199371c9d4SSatish Balay           } else {
172095a0b26dSToby Isaac             /* find where to put this portion of pointMat into the matrix */
172195a0b26dSToby Isaac             for (k = 0; k < numFillCols; k++) {
1722ad540459SPierre Jolivet               if (ja[matOffset + k] == aOff) break;
172395a0b26dSToby Isaac             }
172463a3b9bcSJacob Faibussowitsch             PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
172595a0b26dSToby Isaac             for (r = 0; r < cDof; r++) {
1726085f0adfSToby Isaac               for (j = 0; j < aDof; j++) {
1727085f0adfSToby Isaac                 PetscInt col = perm ? perm[j] : j;
1728085f0adfSToby Isaac 
1729085f0adfSToby Isaac                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
173095a0b26dSToby Isaac               }
173195a0b26dSToby Isaac             }
173295a0b26dSToby Isaac           }
173395a0b26dSToby Isaac           offset += aDof;
173495a0b26dSToby Isaac         }
1735085f0adfSToby Isaac         if (numFields) {
17369566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1737085f0adfSToby Isaac         } else {
17389566063dSJacob Faibussowitsch           PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips));
1739085f0adfSToby Isaac         }
174095a0b26dSToby Isaac       }
17419566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
174295a0b26dSToby Isaac     }
174348a46eb9SPierre Jolivet     for (row = 0; row < nRows; row++) PetscCall(MatSetValues(cMat, 1, &row, ia[row + 1] - ia[row], &ja[ia[row]], &vals[ia[row]], INSERT_VALUES));
17449566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
174528b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix");
17469566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
17479566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
17489566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
174995a0b26dSToby Isaac   }
175095a0b26dSToby Isaac 
175195a0b26dSToby Isaac   /* clean up */
17529566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(anIS, &anchors));
17539566063dSJacob Faibussowitsch   PetscCall(PetscFree2(perm, iperm));
17549566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointWork));
17559566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
17563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
175795a0b26dSToby Isaac }
175895a0b26dSToby Isaac 
17596f5f1567SToby Isaac /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
17606f5f1567SToby Isaac  * a non-conforming mesh.  Local refinement comes later */
DMPlexTreeRefineCell(DM dm,PetscInt cell,DM * ncdm)1761d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm)
1762d71ae5a4SJacob Faibussowitsch {
17636f5f1567SToby Isaac   DM           K;
1764420f55faSMatthew G. Knepley   PetscMPIInt  rank;
17656f5f1567SToby Isaac   PetscInt     dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
17666f5f1567SToby Isaac   PetscInt     numNewCones, *newConeSizes, *newCones, *newOrientations;
17676f5f1567SToby Isaac   PetscInt    *Kembedding;
17686f5f1567SToby Isaac   PetscInt    *cellClosure = NULL, nc;
17696f5f1567SToby Isaac   PetscScalar *newVertexCoords;
17706f5f1567SToby Isaac   PetscInt     numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
17716f5f1567SToby Isaac   PetscSection parentSection;
17726f5f1567SToby Isaac 
17736f5f1567SToby Isaac   PetscFunctionBegin;
17749566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
17759566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17769566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
17779566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*ncdm, dim));
17786f5f1567SToby Isaac 
17799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17809566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection));
17819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &K));
17826858538eSMatthew G. Knepley   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1783dd400576SPatrick Sanan   if (rank == 0) {
17846f5f1567SToby Isaac     /* compute the new charts */
17859566063dSJacob Faibussowitsch     PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd));
17866f5f1567SToby Isaac     offset = 0;
17876f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
17886f5f1567SToby Isaac       PetscInt pOldCount, kStart, kEnd, k;
17896f5f1567SToby Isaac 
17906f5f1567SToby Isaac       pNewStart[d] = offset;
17919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d]));
17929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
17936f5f1567SToby Isaac       pOldCount = pOldEnd[d] - pOldStart[d];
17946f5f1567SToby Isaac       /* adding the new points */
17956f5f1567SToby Isaac       pNewCount[d] = pOldCount + kEnd - kStart;
17966f5f1567SToby Isaac       if (!d) {
17976f5f1567SToby Isaac         /* removing the cell */
17986f5f1567SToby Isaac         pNewCount[d]--;
17996f5f1567SToby Isaac       }
18006f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18016f5f1567SToby Isaac         PetscInt parent;
18029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL));
18036f5f1567SToby Isaac         if (parent == k) {
18046f5f1567SToby Isaac           /* avoid double counting points that won't actually be new */
18056f5f1567SToby Isaac           pNewCount[d]--;
18066f5f1567SToby Isaac         }
18076f5f1567SToby Isaac       }
18086f5f1567SToby Isaac       pNewEnd[d] = pNewStart[d] + pNewCount[d];
18096f5f1567SToby Isaac       offset     = pNewEnd[d];
18106f5f1567SToby Isaac     }
18111dca8a05SBarry 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]);
18126f5f1567SToby Isaac     /* get the current closure of the cell that we are removing */
18139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
18146f5f1567SToby Isaac 
18159566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes));
18166f5f1567SToby Isaac     {
1817b5a892a1SMatthew G. Knepley       DMPolytopeType pct, qct;
18186f5f1567SToby Isaac       PetscInt       kStart, kEnd, k, closureSizeK, *closureK = NULL, j;
18196f5f1567SToby Isaac 
18209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetChart(K, &kStart, &kEnd));
18219566063dSJacob Faibussowitsch       PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient));
18226f5f1567SToby Isaac 
18236f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18246f5f1567SToby Isaac         perm[k - kStart]      = k;
18256f5f1567SToby Isaac         iperm[k - kStart]     = k - kStart;
18266f5f1567SToby Isaac         preOrient[k - kStart] = 0;
18276f5f1567SToby Isaac       }
18286f5f1567SToby Isaac 
18299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18306f5f1567SToby Isaac       for (j = 1; j < closureSizeK; j++) {
18316f5f1567SToby Isaac         PetscInt parentOrientA = closureK[2 * j + 1];
18326f5f1567SToby Isaac         PetscInt parentOrientB = cellClosure[2 * j + 1];
18336f5f1567SToby Isaac         PetscInt p, q;
18346f5f1567SToby Isaac 
18356f5f1567SToby Isaac         p = closureK[2 * j];
18366f5f1567SToby Isaac         q = cellClosure[2 * j];
18379566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, p, &pct));
18389566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, q, &qct));
18396f5f1567SToby Isaac         for (d = 0; d <= dim; d++) {
1840ad540459SPierre Jolivet           if (q >= pOldStart[d] && q < pOldEnd[d]) Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
18416f5f1567SToby Isaac         }
1842b5a892a1SMatthew G. Knepley         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1843b5a892a1SMatthew G. Knepley         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
18446f5f1567SToby Isaac         if (parentOrientA != parentOrientB) {
18456f5f1567SToby Isaac           PetscInt        numChildren, i;
18466f5f1567SToby Isaac           const PetscInt *children;
18476f5f1567SToby Isaac 
18489566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children));
18496f5f1567SToby Isaac           for (i = 0; i < numChildren; i++) {
18506f5f1567SToby Isaac             PetscInt kPerm, oPerm;
18516f5f1567SToby Isaac 
18526f5f1567SToby Isaac             k = children[i];
18539566063dSJacob Faibussowitsch             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm));
18546f5f1567SToby Isaac             /* perm = what refTree position I'm in */
18556f5f1567SToby Isaac             perm[kPerm - kStart] = k;
18566f5f1567SToby Isaac             /* iperm = who is at this position */
18576f5f1567SToby Isaac             iperm[k - kStart]         = kPerm - kStart;
18586f5f1567SToby Isaac             preOrient[kPerm - kStart] = oPerm;
18596f5f1567SToby Isaac           }
18606f5f1567SToby Isaac         }
18616f5f1567SToby Isaac       }
18629566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
18636f5f1567SToby Isaac     }
18649566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim]));
18656f5f1567SToby Isaac     offset      = 0;
18666f5f1567SToby Isaac     numNewCones = 0;
18676f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
18686f5f1567SToby Isaac       PetscInt kStart, kEnd, k;
18696f5f1567SToby Isaac       PetscInt p;
18706f5f1567SToby Isaac       PetscInt size;
18716f5f1567SToby Isaac 
18726f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
18736f5f1567SToby Isaac         /* skip cell 0 */
18746f5f1567SToby Isaac         if (p == cell) continue;
18756f5f1567SToby Isaac         /* old cones to new cones */
18769566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
18776f5f1567SToby Isaac         newConeSizes[offset++] = size;
18786f5f1567SToby Isaac         numNewCones += size;
18796f5f1567SToby Isaac       }
18806f5f1567SToby Isaac 
18819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
18826f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
18836f5f1567SToby Isaac         PetscInt kParent;
18846f5f1567SToby Isaac 
18859566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
18866f5f1567SToby Isaac         if (kParent != k) {
18876f5f1567SToby Isaac           Kembedding[k] = offset;
18889566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
18896f5f1567SToby Isaac           newConeSizes[offset++] = size;
18906f5f1567SToby Isaac           numNewCones += size;
189148a46eb9SPierre Jolivet           if (kParent != 0) PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1));
18926f5f1567SToby Isaac         }
18936f5f1567SToby Isaac       }
18946f5f1567SToby Isaac     }
18956f5f1567SToby Isaac 
18969566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
18979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents));
18989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations));
18999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs));
19006f5f1567SToby Isaac 
19016f5f1567SToby Isaac     /* fill new cones */
19026f5f1567SToby Isaac     offset = 0;
19036f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
19046f5f1567SToby Isaac       PetscInt        kStart, kEnd, k, l;
19056f5f1567SToby Isaac       PetscInt        p;
19066f5f1567SToby Isaac       PetscInt        size;
19076f5f1567SToby Isaac       const PetscInt *cone, *orientation;
19086f5f1567SToby Isaac 
19096f5f1567SToby Isaac       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
19106f5f1567SToby Isaac         /* skip cell 0 */
19116f5f1567SToby Isaac         if (p == cell) continue;
19126f5f1567SToby Isaac         /* old cones to new cones */
19139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, p, &size));
19149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, p, &cone));
19159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeOrientation(dm, p, &orientation));
19166f5f1567SToby Isaac         for (l = 0; l < size; l++) {
19176f5f1567SToby Isaac           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
19186f5f1567SToby Isaac           newOrientations[offset++] = orientation[l];
19196f5f1567SToby Isaac         }
19206f5f1567SToby Isaac       }
19216f5f1567SToby Isaac 
19229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
19236f5f1567SToby Isaac       for (k = kStart; k < kEnd; k++) {
19246f5f1567SToby Isaac         PetscInt kPerm = perm[k], kParent;
19256f5f1567SToby Isaac         PetscInt preO  = preOrient[k];
19266f5f1567SToby Isaac 
19279566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
19286f5f1567SToby Isaac         if (kParent != k) {
19296f5f1567SToby Isaac           /* embed new cones */
19309566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(K, k, &size));
19319566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCone(K, kPerm, &cone));
19329566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation));
19336f5f1567SToby Isaac           for (l = 0; l < size; l++) {
19346f5f1567SToby Isaac             PetscInt       q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size);
19356f5f1567SToby Isaac             PetscInt       newO, lSize, oTrue;
1936b5a892a1SMatthew G. Knepley             DMPolytopeType ct = DM_NUM_POLYTOPES;
19376f5f1567SToby Isaac 
19386f5f1567SToby Isaac             q                = iperm[cone[m]];
19396f5f1567SToby Isaac             newCones[offset] = Kembedding[q];
19409566063dSJacob Faibussowitsch             PetscCall(DMPlexGetConeSize(K, q, &lSize));
1941b5a892a1SMatthew G. Knepley             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
1942b5a892a1SMatthew G. Knepley             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
1943b5a892a1SMatthew G. Knepley             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
19446f5f1567SToby Isaac             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
19456f5f1567SToby Isaac             newO                      = DihedralCompose(lSize, oTrue, preOrient[q]);
1946b5a892a1SMatthew G. Knepley             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
19476f5f1567SToby Isaac           }
19486f5f1567SToby Isaac           if (kParent != 0) {
19496f5f1567SToby Isaac             PetscInt newPoint = Kembedding[kParent];
19509566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset));
19516f5f1567SToby Isaac             parents[pOffset]  = newPoint;
19526f5f1567SToby Isaac             childIDs[pOffset] = k;
19536f5f1567SToby Isaac           }
19546f5f1567SToby Isaac         }
19556f5f1567SToby Isaac       }
19566f5f1567SToby Isaac     }
19576f5f1567SToby Isaac 
19589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords));
19596f5f1567SToby Isaac 
19606f5f1567SToby Isaac     /* fill coordinates */
19616f5f1567SToby Isaac     offset = 0;
19626f5f1567SToby Isaac     {
1963d90620a3SMatthew G. Knepley       PetscInt     kStart, kEnd, l;
19646f5f1567SToby Isaac       PetscSection vSection;
19656f5f1567SToby Isaac       PetscInt     v;
19666f5f1567SToby Isaac       Vec          coords;
19676f5f1567SToby Isaac       PetscScalar *coordvals;
19686f5f1567SToby Isaac       PetscInt     dof, off;
1969c111c6b7SMatthew G. Knepley       PetscReal    v0[3], J[9], detJ;
19706f5f1567SToby Isaac 
197176bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
1972d90620a3SMatthew G. Knepley         PetscInt k;
19739566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd));
19746f5f1567SToby Isaac         for (k = kStart; k < kEnd; k++) {
19759566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
197663a3b9bcSJacob Faibussowitsch           PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k);
19776f5f1567SToby Isaac         }
1978d90620a3SMatthew G. Knepley       }
19799566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
19809566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(dm, &vSection));
19819566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coords));
19829566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19836f5f1567SToby Isaac       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
19849566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(vSection, v, &dof));
19859566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(vSection, v, &off));
1986ad540459SPierre Jolivet         for (l = 0; l < dof; l++) newVertexCoords[offset++] = coordvals[off + l];
19876f5f1567SToby Isaac       }
19889566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
19896f5f1567SToby Isaac 
19909566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(K, &vSection));
19919566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(K, &coords));
19929566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coords, &coordvals));
19939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd));
19946f5f1567SToby Isaac       for (v = kStart; v < kEnd; v++) {
19959bc368c7SMatthew G. Knepley         PetscReal       coord[3], newCoord[3];
19966f5f1567SToby Isaac         PetscInt        vPerm = perm[v];
19976f5f1567SToby Isaac         PetscInt        kParent;
1998c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
19996f5f1567SToby Isaac 
20009566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL));
20016f5f1567SToby Isaac         if (kParent != v) {
20026f5f1567SToby Isaac           /* this is a new vertex */
20039566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(vSection, vPerm, &off));
20049bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]);
2005367003a6SStefano Zampini           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
20069bc368c7SMatthew G. Knepley           for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l];
20076f5f1567SToby Isaac           offset += dim;
20086f5f1567SToby Isaac         }
20096f5f1567SToby Isaac       }
20109566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coords, &coordvals));
20116f5f1567SToby Isaac     }
20126f5f1567SToby Isaac 
20136f5f1567SToby Isaac     /* need to reverse the order of pNewCount: vertices first, cells last */
20146f5f1567SToby Isaac     for (d = 0; d < (dim + 1) / 2; d++) {
20156f5f1567SToby Isaac       PetscInt tmp;
20166f5f1567SToby Isaac 
20176f5f1567SToby Isaac       tmp                = pNewCount[d];
20186f5f1567SToby Isaac       pNewCount[d]       = pNewCount[dim - d];
20196f5f1567SToby Isaac       pNewCount[dim - d] = tmp;
20206f5f1567SToby Isaac     }
20216f5f1567SToby Isaac 
20229566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords));
20239566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20249566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs));
20256f5f1567SToby Isaac 
20266f5f1567SToby Isaac     /* clean up */
20279566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
20289566063dSJacob Faibussowitsch     PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd));
20299566063dSJacob Faibussowitsch     PetscCall(PetscFree(newConeSizes));
20309566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCones, newOrientations));
20319566063dSJacob Faibussowitsch     PetscCall(PetscFree(newVertexCoords));
20329566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parents, childIDs));
20339566063dSJacob Faibussowitsch     PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient));
20349371c9d4SSatish Balay   } else {
20356f5f1567SToby Isaac     PetscInt     p, counts[4];
20366f5f1567SToby Isaac     PetscInt    *coneSizes, *cones, *orientations;
20376f5f1567SToby Isaac     Vec          coordVec;
20386f5f1567SToby Isaac     PetscScalar *coords;
20396f5f1567SToby Isaac 
20406f5f1567SToby Isaac     for (d = 0; d <= dim; d++) {
20416f5f1567SToby Isaac       PetscInt dStart, dEnd;
20426f5f1567SToby Isaac 
20439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
20446f5f1567SToby Isaac       counts[d] = dEnd - dStart;
20456f5f1567SToby Isaac     }
20469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes));
204748a46eb9SPierre Jolivet     for (p = pStart; p < pEnd; p++) PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart]));
20489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCones(dm, &cones));
20499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
20509566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
20519566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordVec, &coords));
20526f5f1567SToby Isaac 
20539566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
20549566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
20559566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL));
20569566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
20579566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL));
20589566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordVec, &coords));
20596f5f1567SToby Isaac   }
20609566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&parentSection));
20613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20626f5f1567SToby Isaac }
20636ecaa68aSToby Isaac 
DMPlexComputeInterpolatorTree(DM coarse,DM fine,PetscSF coarseToFine,PetscInt * childIds,Mat mat)2064d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
2065d71ae5a4SJacob Faibussowitsch {
20666ecaa68aSToby Isaac   PetscSF              coarseToFineEmbedded;
20676ecaa68aSToby Isaac   PetscSection         globalCoarse, globalFine;
20686ecaa68aSToby Isaac   PetscSection         localCoarse, localFine;
20696ecaa68aSToby Isaac   PetscSection         aSec, cSec;
20706ecaa68aSToby Isaac   PetscSection         rootIndicesSec, rootMatricesSec;
207146bdb399SToby Isaac   PetscSection         leafIndicesSec, leafMatricesSec;
207246bdb399SToby Isaac   PetscInt            *rootIndices, *leafIndices;
207346bdb399SToby Isaac   PetscScalar         *rootMatrices, *leafMatrices;
20746ecaa68aSToby Isaac   IS                   aIS;
20756ecaa68aSToby Isaac   const PetscInt      *anchors;
20766ecaa68aSToby Isaac   Mat                  cMat;
20774acb8e1eSToby Isaac   PetscInt             numFields, maxFields;
20786ecaa68aSToby Isaac   PetscInt             pStartC, pEndC, pStartF, pEndF, p;
20796ecaa68aSToby Isaac   PetscInt             aStart, aEnd, cStart, cEnd;
20801c58ffc4SToby Isaac   PetscInt            *maxChildIds;
2081e44e4e7fSToby Isaac   PetscInt            *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
20824acb8e1eSToby Isaac   const PetscInt    ***perms;
20834acb8e1eSToby Isaac   const PetscScalar ***flips;
20846ecaa68aSToby Isaac 
20856ecaa68aSToby Isaac   PetscFunctionBegin;
20869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
20879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
20889566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
20896ecaa68aSToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
209089698031SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
209189698031SToby Isaac     const PetscInt *leaves;
20926ecaa68aSToby Isaac 
20939566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
209489698031SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
209589698031SToby Isaac       p = leaves ? leaves[l] : l;
20969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
20979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2098ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
20996ecaa68aSToby Isaac     }
21009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
21017cc7abc7SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
210289698031SToby Isaac       p = leaves ? leaves[l] : l;
21039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
21049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2105ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
21066ecaa68aSToby Isaac     }
21079566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
21089566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
21096ecaa68aSToby Isaac   }
21106ecaa68aSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
21119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
2112ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
211357168dbeSPierre Jolivet   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211457168dbeSPierre Jolivet   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
211546bdb399SToby Isaac 
21169566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
21179566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
211846bdb399SToby Isaac 
21199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
21209566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
21219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
212246bdb399SToby Isaac 
21239566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
21249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
212546bdb399SToby Isaac 
212646bdb399SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
21279566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
21289566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec));
21299566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC));
21309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC));
21319566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
2132713c1c5dSToby Isaac   maxFields = PetscMax(1, numFields);
21339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO));
21349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips));
21359566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **)));
21369566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **)));
213746bdb399SToby Isaac 
213846bdb399SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
21398d2f55e7SToby Isaac     PetscInt dof, matSize = 0;
21406ecaa68aSToby Isaac     PetscInt aDof          = 0;
21416ecaa68aSToby Isaac     PetscInt cDof          = 0;
21426ecaa68aSToby Isaac     PetscInt maxChildId    = maxChildIds[p - pStartC];
21436ecaa68aSToby Isaac     PetscInt numRowIndices = 0;
21446ecaa68aSToby Isaac     PetscInt numColIndices = 0;
2145f13f9184SToby Isaac     PetscInt f;
21466ecaa68aSToby Isaac 
21479566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2148ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
214948a46eb9SPierre Jolivet     if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
215048a46eb9SPierre Jolivet     if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(cSec, p, &cDof));
2151f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2152f13f9184SToby Isaac     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
21536ecaa68aSToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2154f13f9184SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
21556ecaa68aSToby Isaac 
21569566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
215746bdb399SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
21586ecaa68aSToby Isaac         PetscInt c = closure[2 * cl], clDof;
21596ecaa68aSToby Isaac 
21609566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
21616ecaa68aSToby Isaac         numRowIndices += clDof;
21626ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21639566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof));
21646ecaa68aSToby Isaac           offsets[f + 1] += clDof;
21656ecaa68aSToby Isaac         }
21666ecaa68aSToby Isaac       }
21676ecaa68aSToby Isaac       for (f = 0; f < numFields; f++) {
21686ecaa68aSToby Isaac         offsets[f + 1] += offsets[f];
21696ecaa68aSToby Isaac         newOffsets[f + 1] = offsets[f + 1];
21706ecaa68aSToby Isaac       }
217146bdb399SToby Isaac       /* get the number of indices needed and their field offsets */
21729566063dSJacob Faibussowitsch       PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE));
21739566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
21746ecaa68aSToby Isaac       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
21756ecaa68aSToby Isaac         numColIndices = numRowIndices;
21766ecaa68aSToby Isaac         matSize       = 0;
21779371c9d4SSatish Balay       } else if (numFields) { /* we send one submat for each field: sum their sizes */
21786ecaa68aSToby Isaac         matSize = 0;
21796ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21806ecaa68aSToby Isaac           PetscInt numRow, numCol;
21816ecaa68aSToby Isaac 
21826ecaa68aSToby Isaac           numRow = offsets[f + 1] - offsets[f];
2183f13f9184SToby Isaac           numCol = newOffsets[f + 1] - newOffsets[f];
21846ecaa68aSToby Isaac           matSize += numRow * numCol;
21856ecaa68aSToby Isaac         }
21869371c9d4SSatish Balay       } else {
21876ecaa68aSToby Isaac         matSize = numRowIndices * numColIndices;
21886ecaa68aSToby Isaac       }
2189f13f9184SToby Isaac     } else if (maxChildId == -1) {
21908d2f55e7SToby Isaac       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2191f13f9184SToby Isaac         PetscInt aOff, a;
21926ecaa68aSToby Isaac 
21939566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
21946ecaa68aSToby Isaac         for (f = 0; f < numFields; f++) {
21956ecaa68aSToby Isaac           PetscInt fDof;
21966ecaa68aSToby Isaac 
21979566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
219821968bf8SToby Isaac           offsets[f + 1] = fDof;
21996ecaa68aSToby Isaac         }
22006ecaa68aSToby Isaac         for (a = 0; a < aDof; a++) {
22016ecaa68aSToby Isaac           PetscInt anchor = anchors[a + aOff], aLocalDof;
22026ecaa68aSToby Isaac 
22039566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof));
22046ecaa68aSToby Isaac           numColIndices += aLocalDof;
22056ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
22066ecaa68aSToby Isaac             PetscInt fDof;
22076ecaa68aSToby Isaac 
22089566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
220921968bf8SToby Isaac             newOffsets[f + 1] += fDof;
22106ecaa68aSToby Isaac           }
22116ecaa68aSToby Isaac         }
22126ecaa68aSToby Isaac         if (numFields) {
22136ecaa68aSToby Isaac           matSize = 0;
2214ad540459SPierre Jolivet           for (f = 0; f < numFields; f++) matSize += offsets[f + 1] * newOffsets[f + 1];
22159371c9d4SSatish Balay         } else {
22166ecaa68aSToby Isaac           matSize = numColIndices * dof;
22176ecaa68aSToby Isaac         }
22189371c9d4SSatish Balay       } else { /* no children, and no constraints on dofs: just get the global indices */
22196ecaa68aSToby Isaac         numColIndices = dof;
22206ecaa68aSToby Isaac         matSize       = 0;
22216ecaa68aSToby Isaac       }
22228d2f55e7SToby Isaac     }
222346bdb399SToby Isaac     /* we will pack the column indices with the field offsets */
22249566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0));
22259566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize));
22266ecaa68aSToby Isaac   }
22279566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootIndicesSec));
22289566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootMatricesSec));
22296ecaa68aSToby Isaac   {
22306ecaa68aSToby Isaac     PetscInt numRootIndices, numRootMatrices;
22316ecaa68aSToby Isaac 
22329566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
22339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices));
22349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices));
22356ecaa68aSToby Isaac     for (p = pStartC; p < pEndC; p++) {
22367853b79dSToby Isaac       PetscInt     numRowIndices = 0, numColIndices, matSize, dof;
2237f13f9184SToby Isaac       PetscInt     pIndOff, pMatOff, f;
22386ecaa68aSToby Isaac       PetscInt    *pInd;
22396ecaa68aSToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
22406ecaa68aSToby Isaac       PetscScalar *pMat       = NULL;
22416ecaa68aSToby Isaac 
22429566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
2243ad540459SPierre Jolivet       if (!numColIndices) continue;
2244f13f9184SToby Isaac       for (f = 0; f <= numFields; f++) {
2245f13f9184SToby Isaac         offsets[f]        = 0;
2246f13f9184SToby Isaac         newOffsets[f]     = 0;
2247f13f9184SToby Isaac         offsetsCopy[f]    = 0;
2248f13f9184SToby Isaac         newOffsetsCopy[f] = 0;
2249f13f9184SToby Isaac       }
22506ecaa68aSToby Isaac       numColIndices -= 2 * numFields;
22519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
2252f4f49eeaSPierre Jolivet       pInd = &rootIndices[pIndOff];
22539566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize));
22546ecaa68aSToby Isaac       if (matSize) {
22559566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff));
22566ecaa68aSToby Isaac         pMat = &rootMatrices[pMatOff];
22576ecaa68aSToby Isaac       }
22589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2259ad540459SPierre Jolivet       if (dof < 0) dof = -(dof + 1);
22606ecaa68aSToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
22616ecaa68aSToby Isaac         PetscInt i, j;
22626ecaa68aSToby Isaac 
22637853b79dSToby Isaac         if (matSize == 0) { /* don't need to calculate the mat, just the indices */
22646ecaa68aSToby Isaac           PetscInt numIndices, *indices;
22659566063dSJacob Faibussowitsch           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
226608401ef6SPierre Jolivet           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
2267ad540459SPierre Jolivet           for (i = 0; i < numColIndices; i++) pInd[i] = indices[i];
22686ecaa68aSToby Isaac           for (i = 0; i < numFields; i++) {
226946bdb399SToby Isaac             pInd[numColIndices + i]             = offsets[i + 1];
227046bdb399SToby Isaac             pInd[numColIndices + numFields + i] = offsets[i + 1];
22716ecaa68aSToby Isaac           }
22729566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
22739371c9d4SSatish Balay         } else {
22746ecaa68aSToby Isaac           PetscInt     closureSize, *closure = NULL, cl;
22756ecaa68aSToby Isaac           PetscScalar *pMatIn, *pMatModified;
22766ecaa68aSToby Isaac           PetscInt     numPoints, *points;
22776ecaa68aSToby Isaac 
22787853b79dSToby Isaac           {
22797853b79dSToby Isaac             PetscInt *closure = NULL, closureSize, cl;
22807853b79dSToby Isaac 
22817853b79dSToby Isaac             PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22827853b79dSToby Isaac             for (cl = 0; cl < closureSize; cl++) { /* get the closure */
22837853b79dSToby Isaac               PetscInt c = closure[2 * cl], clDof;
22847853b79dSToby Isaac 
22857853b79dSToby Isaac               PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
22867853b79dSToby Isaac               numRowIndices += clDof;
22877853b79dSToby Isaac             }
22887853b79dSToby Isaac             PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22897853b79dSToby Isaac           }
22907853b79dSToby Isaac 
22919566063dSJacob Faibussowitsch           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
22926ecaa68aSToby Isaac           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2293ad540459SPierre Jolivet             for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
22946ecaa68aSToby Isaac           }
22959566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
22964acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
22979566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
22989566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
22994acb8e1eSToby Isaac           }
23006ecaa68aSToby Isaac           if (numFields) {
23016ecaa68aSToby Isaac             for (cl = 0; cl < closureSize; cl++) {
23026ecaa68aSToby Isaac               PetscInt c = closure[2 * cl];
23036ecaa68aSToby Isaac 
23046ecaa68aSToby Isaac               for (f = 0; f < numFields; f++) {
23056ecaa68aSToby Isaac                 PetscInt fDof;
23066ecaa68aSToby Isaac 
23079566063dSJacob Faibussowitsch                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
23086ecaa68aSToby Isaac                 offsets[f + 1] += fDof;
23096ecaa68aSToby Isaac               }
23106ecaa68aSToby Isaac             }
23116ecaa68aSToby Isaac             for (f = 0; f < numFields; f++) {
23126ecaa68aSToby Isaac               offsets[f + 1] += offsets[f];
23136ecaa68aSToby Isaac               newOffsets[f + 1] = offsets[f + 1];
23146ecaa68aSToby Isaac             }
23156ecaa68aSToby Isaac           }
23164acb8e1eSToby Isaac           /* TODO : flips here ? */
23176ecaa68aSToby Isaac           /* apply hanging node constraints on the right, get the new points and the new offsets */
23189566063dSJacob Faibussowitsch           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
23194acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23209566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
23219566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
23224acb8e1eSToby Isaac           }
23234acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23249566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23259566063dSJacob Faibussowitsch             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23264acb8e1eSToby Isaac           }
23276ecaa68aSToby Isaac           if (!numFields) {
2328ad540459SPierre Jolivet             for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i];
23299371c9d4SSatish Balay           } else {
2330f13f9184SToby Isaac             PetscInt i, j, count;
23316ecaa68aSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
23326ecaa68aSToby Isaac               for (i = offsets[f]; i < offsets[f + 1]; i++) {
2333ad540459SPierre Jolivet                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j];
23346ecaa68aSToby Isaac               }
23356ecaa68aSToby Isaac             }
23366ecaa68aSToby Isaac           }
23379566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
23389566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
23399566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
23406ecaa68aSToby Isaac           if (numFields) {
234146bdb399SToby Isaac             for (f = 0; f < numFields; f++) {
234246bdb399SToby Isaac               pInd[numColIndices + f]             = offsets[f + 1];
234346bdb399SToby Isaac               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
23446ecaa68aSToby Isaac             }
23454acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23464acb8e1eSToby Isaac               PetscInt globalOff, c = points[2 * cl];
23479566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23489566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
23496ecaa68aSToby Isaac             }
23506ecaa68aSToby Isaac           } else {
23514acb8e1eSToby Isaac             for (cl = 0; cl < numPoints; cl++) {
23524acb8e1eSToby Isaac               PetscInt        c    = points[2 * cl], globalOff;
23534acb8e1eSToby Isaac               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;
23544acb8e1eSToby Isaac 
23559566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
23569566063dSJacob Faibussowitsch               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
23576ecaa68aSToby Isaac             }
23586ecaa68aSToby Isaac           }
23594acb8e1eSToby Isaac           for (f = 0; f < maxFields; f++) {
23609566063dSJacob Faibussowitsch             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
23619566063dSJacob Faibussowitsch             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
23624acb8e1eSToby Isaac           }
23639566063dSJacob Faibussowitsch           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
23646ecaa68aSToby Isaac         }
23659371c9d4SSatish Balay       } else if (matSize) {
23666ecaa68aSToby Isaac         PetscInt  cOff;
23677853b79dSToby Isaac         PetscInt *rowIndices, *colIndices, a, aDof = 0, aOff;
23686ecaa68aSToby Isaac 
23697853b79dSToby Isaac         numRowIndices = dof;
23709566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
23719566063dSJacob Faibussowitsch         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
23729566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
23739566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
23749566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
23756ecaa68aSToby Isaac         if (numFields) {
23766ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23776ecaa68aSToby Isaac             PetscInt fDof;
2378f13f9184SToby Isaac 
23799566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
23806ecaa68aSToby Isaac             offsets[f + 1] = fDof;
23816ecaa68aSToby Isaac             for (a = 0; a < aDof; a++) {
23826ecaa68aSToby Isaac               PetscInt anchor = anchors[a + aOff];
23839566063dSJacob Faibussowitsch               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
23846ecaa68aSToby Isaac               newOffsets[f + 1] += fDof;
23856ecaa68aSToby Isaac             }
23866ecaa68aSToby Isaac           }
23876ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
23886ecaa68aSToby Isaac             offsets[f + 1] += offsets[f];
23896ecaa68aSToby Isaac             offsetsCopy[f + 1] = offsets[f + 1];
23906ecaa68aSToby Isaac             newOffsets[f + 1] += newOffsets[f];
23916ecaa68aSToby Isaac             newOffsetsCopy[f + 1] = newOffsets[f + 1];
23926ecaa68aSToby Isaac           }
23939566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
23946ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
23956ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
23969566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
23979566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
23986ecaa68aSToby Isaac           }
23999371c9d4SSatish Balay         } else {
24009566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
24016ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24026ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff], lOff;
24039566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
24049566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
24056ecaa68aSToby Isaac           }
24066ecaa68aSToby Isaac         }
24076ecaa68aSToby Isaac         if (numFields) {
2408f13f9184SToby Isaac           PetscInt count, a;
2409f13f9184SToby Isaac 
24106ecaa68aSToby Isaac           for (f = 0, count = 0; f < numFields; f++) {
24116ecaa68aSToby Isaac             PetscInt iSize = offsets[f + 1] - offsets[f];
24126ecaa68aSToby Isaac             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
24139566063dSJacob Faibussowitsch             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
24146ecaa68aSToby Isaac             count += iSize * jSize;
241546bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
241646bdb399SToby Isaac             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
24176ecaa68aSToby Isaac           }
24186ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24196ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24206ecaa68aSToby Isaac             PetscInt gOff;
24219566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24229566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
24236ecaa68aSToby Isaac           }
24249371c9d4SSatish Balay         } else {
24256ecaa68aSToby Isaac           PetscInt a;
24269566063dSJacob Faibussowitsch           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
24276ecaa68aSToby Isaac           for (a = 0; a < aDof; a++) {
24286ecaa68aSToby Isaac             PetscInt anchor = anchors[a + aOff];
24296ecaa68aSToby Isaac             PetscInt gOff;
24309566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
24319566063dSJacob Faibussowitsch             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
24326ecaa68aSToby Isaac           }
24336ecaa68aSToby Isaac         }
24349566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
24359566063dSJacob Faibussowitsch         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
24369371c9d4SSatish Balay       } else {
24376ecaa68aSToby Isaac         PetscInt gOff;
24386ecaa68aSToby Isaac 
24399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
24406ecaa68aSToby Isaac         if (numFields) {
24416ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
24426ecaa68aSToby Isaac             PetscInt fDof;
24439566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
24446ecaa68aSToby Isaac             offsets[f + 1] = fDof + offsets[f];
24456ecaa68aSToby Isaac           }
24466ecaa68aSToby Isaac           for (f = 0; f < numFields; f++) {
244746bdb399SToby Isaac             pInd[numColIndices + f]             = offsets[f + 1];
244846bdb399SToby Isaac             pInd[numColIndices + numFields + f] = offsets[f + 1];
24496ecaa68aSToby Isaac           }
24509566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2451367003a6SStefano Zampini         } else {
24529566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
24536ecaa68aSToby Isaac         }
24546ecaa68aSToby Isaac       }
24556ecaa68aSToby Isaac     }
24569566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
24576ecaa68aSToby Isaac   }
245846bdb399SToby Isaac   {
245946bdb399SToby Isaac     PetscSF   indicesSF, matricesSF;
246046bdb399SToby Isaac     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;
246146bdb399SToby Isaac 
24629566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
24639566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
24649566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
24659566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
24669566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
24679566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
24689566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
24699566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsIndices));
24709566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsMatrices));
24719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
24729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
24739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
24749566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24759566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24769566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
24779566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
24789566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&matricesSF));
24799566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
24809566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootIndices, rootMatrices));
24819566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootIndicesSec));
24829566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootMatricesSec));
248346bdb399SToby Isaac   }
248446bdb399SToby Isaac   /* count to preallocate */
24859566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
248646bdb399SToby Isaac   {
248746bdb399SToby Isaac     PetscInt       nGlobal;
248846bdb399SToby Isaac     PetscInt      *dnnz, *onnz;
2489b9a5774bSToby Isaac     PetscLayout    rowMap, colMap;
2490b9a5774bSToby Isaac     PetscInt       rowStart, rowEnd, colStart, colEnd;
24911c58ffc4SToby Isaac     PetscInt       maxDof;
24921c58ffc4SToby Isaac     PetscInt      *rowIndices;
24931c58ffc4SToby Isaac     DM             refTree;
24941c58ffc4SToby Isaac     PetscInt     **refPointFieldN;
24951c58ffc4SToby Isaac     PetscScalar ***refPointFieldMats;
24961c58ffc4SToby Isaac     PetscSection   refConSec, refAnSec;
24970eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
24981c58ffc4SToby Isaac     PetscScalar   *pointWork;
249946bdb399SToby Isaac 
25009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
25019566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
25029566063dSJacob Faibussowitsch     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
25039566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(rowMap));
25049566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(colMap));
25059566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
25069566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
25079566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
25089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
25099566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
25100eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
251146bdb399SToby Isaac       PetscInt gDof, gcDof, gOff;
251246bdb399SToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
251346bdb399SToby Isaac       PetscInt matSize;
251421968bf8SToby Isaac       PetscInt i;
251546bdb399SToby Isaac 
25169566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
25179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2518ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
25199566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
252008401ef6SPierre Jolivet       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
25211dca8a05SBarry Smith       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
25229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
25239566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
252446bdb399SToby Isaac       numColIndices -= 2 * numFields;
252508401ef6SPierre Jolivet       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
252646bdb399SToby Isaac       pInd              = &leafIndices[pIndOff];
252721968bf8SToby Isaac       offsets[0]        = 0;
252821968bf8SToby Isaac       offsetsCopy[0]    = 0;
252921968bf8SToby Isaac       newOffsets[0]     = 0;
253021968bf8SToby Isaac       newOffsetsCopy[0] = 0;
253146bdb399SToby Isaac       if (numFields) {
253221968bf8SToby Isaac         PetscInt f;
253346bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
253446bdb399SToby Isaac           PetscInt rowDof;
253546bdb399SToby Isaac 
25369566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
253721968bf8SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
253821968bf8SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
253921968bf8SToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
254021968bf8SToby Isaac           numD[f]            = 0;
254121968bf8SToby Isaac           numO[f]            = 0;
254246bdb399SToby Isaac         }
25439566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
254446bdb399SToby Isaac         for (f = 0; f < numFields; f++) {
254521968bf8SToby Isaac           PetscInt colOffset    = newOffsets[f];
254621968bf8SToby Isaac           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];
254746bdb399SToby Isaac 
254846bdb399SToby Isaac           for (i = 0; i < numFieldCols; i++) {
254946bdb399SToby Isaac             PetscInt gInd = pInd[i + colOffset];
255046bdb399SToby Isaac 
255146bdb399SToby Isaac             if (gInd >= colStart && gInd < colEnd) {
255221968bf8SToby Isaac               numD[f]++;
25539371c9d4SSatish Balay             } else if (gInd >= 0) { /* negative means non-entry */
255421968bf8SToby Isaac               numO[f]++;
255546bdb399SToby Isaac             }
255646bdb399SToby Isaac           }
255746bdb399SToby Isaac         }
25589371c9d4SSatish Balay       } else {
25599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
256021968bf8SToby Isaac         numD[0] = 0;
256121968bf8SToby Isaac         numO[0] = 0;
256246bdb399SToby Isaac         for (i = 0; i < numColIndices; i++) {
256346bdb399SToby Isaac           PetscInt gInd = pInd[i];
256446bdb399SToby Isaac 
256546bdb399SToby Isaac           if (gInd >= colStart && gInd < colEnd) {
256621968bf8SToby Isaac             numD[0]++;
25679371c9d4SSatish Balay           } else if (gInd >= 0) { /* negative means non-entry */
256821968bf8SToby Isaac             numO[0]++;
256946bdb399SToby Isaac           }
257046bdb399SToby Isaac         }
257146bdb399SToby Isaac       }
25729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
257346bdb399SToby Isaac       if (!matSize) { /* incoming matrix is identity */
257446bdb399SToby Isaac         PetscInt childId;
257546bdb399SToby Isaac 
257646bdb399SToby Isaac         childId = childIds[p - pStartF];
257721968bf8SToby Isaac         if (childId < 0) { /* no child interpolation: one nnz per */
257846bdb399SToby Isaac           if (numFields) {
2579b9a5774bSToby Isaac             PetscInt f;
2580b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
258121968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
258246bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
258321968bf8SToby Isaac                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
258421968bf8SToby Isaac                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
258546bdb399SToby Isaac                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
25861dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2587b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = 1;
25889371c9d4SSatish Balay                 } else if (gIndCoarse >= 0) { /* remote */
25891dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2590b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = 1;
25919371c9d4SSatish Balay                 } else { /* constrained */
259208401ef6SPierre Jolivet                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
259346bdb399SToby Isaac                 }
259446bdb399SToby Isaac               }
259546bdb399SToby Isaac             }
25969371c9d4SSatish Balay           } else {
2597b9a5774bSToby Isaac             PetscInt i;
2598b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
259946bdb399SToby Isaac               PetscInt gIndCoarse = pInd[i];
260046bdb399SToby Isaac               PetscInt gIndFine   = rowIndices[i];
260146bdb399SToby Isaac               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
26021dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2603b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = 1;
26049371c9d4SSatish Balay               } else if (gIndCoarse >= 0) { /* remote */
26051dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2606b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = 1;
26079371c9d4SSatish Balay               } else { /* constrained */
260808401ef6SPierre Jolivet                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
260946bdb399SToby Isaac               }
261046bdb399SToby Isaac             }
261146bdb399SToby Isaac           }
26129371c9d4SSatish Balay         } else { /* interpolate from all */
261346bdb399SToby Isaac           if (numFields) {
2614b9a5774bSToby Isaac             PetscInt f;
2615b9a5774bSToby Isaac             for (f = 0; f < numFields; f++) {
261621968bf8SToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
261746bdb399SToby Isaac               for (row = 0; row < numRows; row++) {
261821968bf8SToby Isaac                 PetscInt gIndFine = rowIndices[offsets[f] + row];
261946bdb399SToby Isaac                 if (gIndFine >= 0) {
26201dca8a05SBarry Smith                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2621b9a5774bSToby Isaac                   dnnz[gIndFine - rowStart] = numD[f];
2622b9a5774bSToby Isaac                   onnz[gIndFine - rowStart] = numO[f];
262346bdb399SToby Isaac                 }
262446bdb399SToby Isaac               }
262546bdb399SToby Isaac             }
26269371c9d4SSatish Balay           } else {
2627b9a5774bSToby Isaac             PetscInt i;
2628b9a5774bSToby Isaac             for (i = 0; i < gDof; i++) {
262946bdb399SToby Isaac               PetscInt gIndFine = rowIndices[i];
263046bdb399SToby Isaac               if (gIndFine >= 0) {
26311dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2632b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[0];
2633b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[0];
263446bdb399SToby Isaac               }
263546bdb399SToby Isaac             }
263646bdb399SToby Isaac           }
263746bdb399SToby Isaac         }
26389371c9d4SSatish Balay       } else { /* interpolate from all */
263946bdb399SToby Isaac         if (numFields) {
2640b9a5774bSToby Isaac           PetscInt f;
2641b9a5774bSToby Isaac           for (f = 0; f < numFields; f++) {
264221968bf8SToby Isaac             PetscInt numRows = offsets[f + 1] - offsets[f], row;
264346bdb399SToby Isaac             for (row = 0; row < numRows; row++) {
264421968bf8SToby Isaac               PetscInt gIndFine = rowIndices[offsets[f] + row];
264546bdb399SToby Isaac               if (gIndFine >= 0) {
26461dca8a05SBarry Smith                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2647b9a5774bSToby Isaac                 dnnz[gIndFine - rowStart] = numD[f];
2648b9a5774bSToby Isaac                 onnz[gIndFine - rowStart] = numO[f];
264946bdb399SToby Isaac               }
265046bdb399SToby Isaac             }
265146bdb399SToby Isaac           }
26529371c9d4SSatish Balay         } else { /* every dof get a full row */
2653b9a5774bSToby Isaac           PetscInt i;
2654b9a5774bSToby Isaac           for (i = 0; i < gDof; i++) {
265546bdb399SToby Isaac             PetscInt gIndFine = rowIndices[i];
265646bdb399SToby Isaac             if (gIndFine >= 0) {
26571dca8a05SBarry Smith               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2658b9a5774bSToby Isaac               dnnz[gIndFine - rowStart] = numD[0];
2659b9a5774bSToby Isaac               onnz[gIndFine - rowStart] = numO[0];
266046bdb399SToby Isaac             }
266146bdb399SToby Isaac           }
266246bdb399SToby Isaac         }
266346bdb399SToby Isaac       }
266446bdb399SToby Isaac     }
26659566063dSJacob Faibussowitsch     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
26669566063dSJacob Faibussowitsch     PetscCall(PetscFree2(dnnz, onnz));
266721968bf8SToby Isaac 
26689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
2669d3a532e9SStefano Zampini     PetscCall(DMCopyDisc(fine, refTree));
2670d3a532e9SStefano Zampini     PetscCall(DMSetLocalSection(refTree, NULL));
2671d3a532e9SStefano Zampini     PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
26729566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
26739566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
26749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
26759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
26769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
26779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
26789566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
26790eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
2680e44e4e7fSToby Isaac       PetscInt gDof, gcDof, gOff;
2681e44e4e7fSToby Isaac       PetscInt numColIndices, pIndOff, *pInd;
2682e44e4e7fSToby Isaac       PetscInt matSize;
2683e44e4e7fSToby Isaac       PetscInt childId;
2684e44e4e7fSToby Isaac 
26859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
26869566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2687ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
2688e44e4e7fSToby Isaac       childId = childIds[p - pStartF];
26899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
26909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
26919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2692e44e4e7fSToby Isaac       numColIndices -= 2 * numFields;
2693e44e4e7fSToby Isaac       pInd              = &leafIndices[pIndOff];
2694e44e4e7fSToby Isaac       offsets[0]        = 0;
2695e44e4e7fSToby Isaac       offsetsCopy[0]    = 0;
2696e44e4e7fSToby Isaac       newOffsets[0]     = 0;
2697e44e4e7fSToby Isaac       newOffsetsCopy[0] = 0;
2698e44e4e7fSToby Isaac       rowOffsets[0]     = 0;
2699e44e4e7fSToby Isaac       if (numFields) {
2700e44e4e7fSToby Isaac         PetscInt f;
2701e44e4e7fSToby Isaac         for (f = 0; f < numFields; f++) {
2702e44e4e7fSToby Isaac           PetscInt rowDof;
2703e44e4e7fSToby Isaac 
27049566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2705e44e4e7fSToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
2706e44e4e7fSToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
2707e44e4e7fSToby Isaac           rowOffsets[f + 1]  = pInd[numColIndices + f];
2708e44e4e7fSToby Isaac           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2709e44e4e7fSToby Isaac         }
27109566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
27119371c9d4SSatish Balay       } else {
27129566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
27131c58ffc4SToby Isaac       }
27149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2715e44e4e7fSToby Isaac       if (!matSize) {      /* incoming matrix is identity */
2716e44e4e7fSToby Isaac         if (childId < 0) { /* no child interpolation: scatter */
2717e44e4e7fSToby Isaac           if (numFields) {
2718e44e4e7fSToby Isaac             PetscInt f;
2719e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2720e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f], row;
272148a46eb9SPierre Jolivet               for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES));
272221968bf8SToby Isaac             }
27239371c9d4SSatish Balay           } else {
2724e44e4e7fSToby Isaac             PetscInt numRows = gDof, row;
272548a46eb9SPierre Jolivet             for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES));
2726e44e4e7fSToby Isaac           }
27279371c9d4SSatish Balay         } else { /* interpolate from all */
2728e44e4e7fSToby Isaac           if (numFields) {
2729e44e4e7fSToby Isaac             PetscInt f;
2730e44e4e7fSToby Isaac             for (f = 0; f < numFields; f++) {
2731e44e4e7fSToby Isaac               PetscInt numRows = offsets[f + 1] - offsets[f];
2732e44e4e7fSToby Isaac               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
27339566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2734e44e4e7fSToby Isaac             }
27359371c9d4SSatish Balay           } else {
27369566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2737e44e4e7fSToby Isaac           }
2738e44e4e7fSToby Isaac         }
27399371c9d4SSatish Balay       } else { /* interpolate from all */
2740e44e4e7fSToby Isaac         PetscInt     pMatOff;
2741e44e4e7fSToby Isaac         PetscScalar *pMat;
2742e44e4e7fSToby Isaac 
27439566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2744e44e4e7fSToby Isaac         pMat = &leafMatrices[pMatOff];
2745e44e4e7fSToby Isaac         if (childId < 0) { /* copy the incoming matrix */
2746e44e4e7fSToby Isaac           if (numFields) {
2747e44e4e7fSToby Isaac             PetscInt f, count;
2748e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2749e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2750e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2751e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2752e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2753e44e4e7fSToby Isaac 
27549566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2755e44e4e7fSToby Isaac               count += numCols * numInRows;
2756e44e4e7fSToby Isaac             }
27579371c9d4SSatish Balay           } else {
27589566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2759e44e4e7fSToby Isaac           }
27609371c9d4SSatish Balay         } else { /* multiply the incoming matrix by the child interpolation */
2761e44e4e7fSToby Isaac           if (numFields) {
2762e44e4e7fSToby Isaac             PetscInt f, count;
2763e44e4e7fSToby Isaac             for (f = 0, count = 0; f < numFields; f++) {
2764e44e4e7fSToby Isaac               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2765e44e4e7fSToby Isaac               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2766e44e4e7fSToby Isaac               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2767e44e4e7fSToby Isaac               PetscScalar *inMat     = &pMat[count];
2768e44e4e7fSToby Isaac               PetscInt     i, j, k;
276908401ef6SPierre Jolivet               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2770e44e4e7fSToby Isaac               for (i = 0; i < numRows; i++) {
2771e44e4e7fSToby Isaac                 for (j = 0; j < numCols; j++) {
2772e44e4e7fSToby Isaac                   PetscScalar val = 0.;
2773ad540459SPierre Jolivet                   for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2774e44e4e7fSToby Isaac                   pointWork[i * numCols + j] = val;
2775e44e4e7fSToby Isaac                 }
2776e44e4e7fSToby Isaac               }
27779566063dSJacob Faibussowitsch               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2778e44e4e7fSToby Isaac               count += numCols * numInRows;
2779e44e4e7fSToby Isaac             }
27809371c9d4SSatish Balay           } else { /* every dof gets a full row */
2781e44e4e7fSToby Isaac             PetscInt numRows   = gDof;
2782e44e4e7fSToby Isaac             PetscInt numCols   = numColIndices;
2783e44e4e7fSToby Isaac             PetscInt numInRows = matSize / numColIndices;
2784e44e4e7fSToby Isaac             PetscInt i, j, k;
278508401ef6SPierre Jolivet             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2786e44e4e7fSToby Isaac             for (i = 0; i < numRows; i++) {
2787e44e4e7fSToby Isaac               for (j = 0; j < numCols; j++) {
2788e44e4e7fSToby Isaac                 PetscScalar val = 0.;
2789ad540459SPierre Jolivet                 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2790e44e4e7fSToby Isaac                 pointWork[i * numCols + j] = val;
2791e44e4e7fSToby Isaac               }
2792e44e4e7fSToby Isaac             }
27939566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2794e44e4e7fSToby Isaac           }
2795e44e4e7fSToby Isaac         }
2796e44e4e7fSToby Isaac       }
2797e44e4e7fSToby Isaac     }
27989566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
27999566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
28009566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointWork));
2801e44e4e7fSToby Isaac   }
28029566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
28039566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
28049566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
28059566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafMatricesSec));
28069566063dSJacob Faibussowitsch   PetscCall(PetscFree2(leafIndices, leafMatrices));
28079566063dSJacob Faibussowitsch   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
28089566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
28099566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
28103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28116ecaa68aSToby Isaac }
2812154bca37SToby Isaac 
28138d2f55e7SToby Isaac /*
28148d2f55e7SToby Isaac  * Assuming a nodal basis (w.r.t. the dual basis) basis:
28158d2f55e7SToby Isaac  *
28168d2f55e7SToby Isaac  * for each coarse dof \phi^c_i:
28178d2f55e7SToby Isaac  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
28188d2f55e7SToby Isaac  *     for each fine dof \phi^f_j;
28198d2f55e7SToby Isaac  *       a_{i,j} = 0;
28208d2f55e7SToby Isaac  *       for each fine dof \phi^f_k:
28218d2f55e7SToby Isaac  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
28228d2f55e7SToby Isaac  *                    [^^^ this is = \phi^c_i ^^^]
28238d2f55e7SToby Isaac  */
DMPlexComputeInjectorReferenceTree(DM refTree,Mat * inj)2824d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
2825d71ae5a4SJacob Faibussowitsch {
28268d2f55e7SToby Isaac   PetscDS      ds;
28278d2f55e7SToby Isaac   PetscSection section, cSection;
28288d2f55e7SToby Isaac   DMLabel      canonical, depth;
28298d2f55e7SToby Isaac   Mat          cMat, mat;
28308d2f55e7SToby Isaac   PetscInt    *nnz;
28318d2f55e7SToby Isaac   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
28328d2f55e7SToby Isaac   PetscInt     m, n;
28338d2f55e7SToby Isaac   PetscScalar *pointScalar;
28348d2f55e7SToby Isaac   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;
28358d2f55e7SToby Isaac 
28368d2f55e7SToby Isaac   PetscFunctionBegin;
28379566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &section));
28389566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(refTree, &dim));
28399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
28409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
28419566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
28429566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
28439566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
28449566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
28459566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(refTree, "depth", &depth));
28469566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
28479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
28489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
28499566063dSJacob Faibussowitsch   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
28508d2f55e7SToby Isaac   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
28519566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(m, &nnz));
28528d2f55e7SToby 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 */
28538d2f55e7SToby Isaac     const PetscInt *children;
28548d2f55e7SToby Isaac     PetscInt        numChildren;
28558d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28568d2f55e7SToby Isaac 
28578d2f55e7SToby Isaac     if (canonical) {
28588d2f55e7SToby Isaac       PetscInt pCanonical;
28599566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
28608d2f55e7SToby Isaac       if (p != pCanonical) continue;
28618d2f55e7SToby Isaac     }
28629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
28638d2f55e7SToby Isaac     if (!numChildren) continue;
28648d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
28658d2f55e7SToby Isaac       PetscInt child = children[i];
28668d2f55e7SToby Isaac       PetscInt dof;
28678d2f55e7SToby Isaac 
28689566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
28698d2f55e7SToby Isaac       numChildDof += dof;
28708d2f55e7SToby Isaac     }
28719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
28728d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
28738d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
28748d2f55e7SToby Isaac       PetscInt selfOff;
28758d2f55e7SToby Isaac 
28768d2f55e7SToby Isaac       if (numSecFields) { /* count the dofs for just this field */
28778d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
28788d2f55e7SToby Isaac           PetscInt child = children[i];
28798d2f55e7SToby Isaac           PetscInt dof;
28808d2f55e7SToby Isaac 
28819566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
28828d2f55e7SToby Isaac           numChildDof += dof;
28838d2f55e7SToby Isaac         }
28849566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
28859566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
28869371c9d4SSatish Balay       } else {
28879566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
28888d2f55e7SToby Isaac       }
2889ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof;
28908d2f55e7SToby Isaac     }
28918d2f55e7SToby Isaac   }
28929566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
28939566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
28948d2f55e7SToby Isaac   /* Setp 2: compute entries */
28958d2f55e7SToby Isaac   for (p = pStart; p < pEnd; p++) {
28968d2f55e7SToby Isaac     const PetscInt *children;
28978d2f55e7SToby Isaac     PetscInt        numChildren;
28988d2f55e7SToby Isaac     PetscInt        i, numChildDof, numSelfDof;
28998d2f55e7SToby Isaac 
29008d2f55e7SToby Isaac     /* same conditions about when entries occur */
29018d2f55e7SToby Isaac     if (canonical) {
29028d2f55e7SToby Isaac       PetscInt pCanonical;
29039566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
29048d2f55e7SToby Isaac       if (p != pCanonical) continue;
29058d2f55e7SToby Isaac     }
29069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
29078d2f55e7SToby Isaac     if (!numChildren) continue;
29088d2f55e7SToby Isaac     for (i = 0, numChildDof = 0; i < numChildren; i++) {
29098d2f55e7SToby Isaac       PetscInt child = children[i];
29108d2f55e7SToby Isaac       PetscInt dof;
29118d2f55e7SToby Isaac 
29129566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, child, &dof));
29138d2f55e7SToby Isaac       numChildDof += dof;
29148d2f55e7SToby Isaac     }
29159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
29168d2f55e7SToby Isaac     if (!numChildDof || !numSelfDof) continue;
29178d2f55e7SToby Isaac 
29188d2f55e7SToby Isaac     for (f = 0; f < numFields; f++) {
291959fc6756SToby Isaac       PetscInt        pI = -1, cI = -1;
292052a3aeb4SToby Isaac       PetscInt        selfOff, Nc, parentCell;
29218d2f55e7SToby Isaac       PetscInt        cellShapeOff;
29228d2f55e7SToby Isaac       PetscObject     disc;
29238d2f55e7SToby Isaac       PetscDualSpace  dsp;
29248d2f55e7SToby Isaac       PetscClassId    classId;
29258d2f55e7SToby Isaac       PetscScalar    *pointMat;
29263b1c2a6aSToby Isaac       PetscInt       *matRows, *matCols;
29271690c2aeSBarry Smith       PetscInt        pO = PETSC_INT_MIN;
29288d2f55e7SToby Isaac       const PetscInt *depthNumDof;
29298d2f55e7SToby Isaac 
29308d2f55e7SToby Isaac       if (numSecFields) {
29318d2f55e7SToby Isaac         for (i = 0, numChildDof = 0; i < numChildren; i++) {
29328d2f55e7SToby Isaac           PetscInt child = children[i];
29338d2f55e7SToby Isaac           PetscInt dof;
29348d2f55e7SToby Isaac 
29359566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
29368d2f55e7SToby Isaac           numChildDof += dof;
29378d2f55e7SToby Isaac         }
29389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
29399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
29409371c9d4SSatish Balay       } else {
29419566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
29428d2f55e7SToby Isaac       }
29438d2f55e7SToby Isaac 
29443b1c2a6aSToby Isaac       /* find a cell whose closure contains p */
29458d2f55e7SToby Isaac       if (p >= cStart && p < cEnd) {
29468d2f55e7SToby Isaac         parentCell = p;
29479371c9d4SSatish Balay       } else {
29488d2f55e7SToby Isaac         PetscInt *star = NULL;
29498d2f55e7SToby Isaac         PetscInt  numStar;
29508d2f55e7SToby Isaac 
29518d2f55e7SToby Isaac         parentCell = -1;
29529566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29538d2f55e7SToby Isaac         for (i = numStar - 1; i >= 0; i--) {
29548d2f55e7SToby Isaac           PetscInt c = star[2 * i];
29558d2f55e7SToby Isaac 
29568d2f55e7SToby Isaac           if (c >= cStart && c < cEnd) {
29578d2f55e7SToby Isaac             parentCell = c;
29588d2f55e7SToby Isaac             break;
29598d2f55e7SToby Isaac           }
29608d2f55e7SToby Isaac         }
29619566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
29628d2f55e7SToby Isaac       }
2963a5b23f4aSJose E. Roman       /* determine the offset of p's shape functions within parentCell's shape functions */
29649566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
29659566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(disc, &classId));
2966c5356c36SToby Isaac       if (classId == PETSCFE_CLASSID) {
29679566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
29689371c9d4SSatish Balay       } else if (classId == PETSCFV_CLASSID) {
29699566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
29709371c9d4SSatish Balay       } else {
29719b90b7cdSMatthew G. Knepley         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2972c5356c36SToby Isaac       }
29739566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
29749566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
29758d2f55e7SToby Isaac       {
29768d2f55e7SToby Isaac         PetscInt *closure = NULL;
29778d2f55e7SToby Isaac         PetscInt  numClosure;
29788d2f55e7SToby Isaac 
29799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
298059fc6756SToby Isaac         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
29818d2f55e7SToby Isaac           PetscInt point = closure[2 * i], pointDepth;
29828d2f55e7SToby Isaac 
29838d2f55e7SToby Isaac           pO = closure[2 * i + 1];
298459fc6756SToby Isaac           if (point == p) {
298559fc6756SToby Isaac             pI = i;
298659fc6756SToby Isaac             break;
298759fc6756SToby Isaac           }
29889566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
29898d2f55e7SToby Isaac           cellShapeOff += depthNumDof[pointDepth];
29908d2f55e7SToby Isaac         }
29919566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
29928d2f55e7SToby Isaac       }
29938d2f55e7SToby Isaac 
29949566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
29959566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
299652a3aeb4SToby Isaac       matCols = matRows + numSelfDof;
2997ad540459SPierre Jolivet       for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i;
299852a3aeb4SToby Isaac       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
29993b1c2a6aSToby Isaac       {
30003b1c2a6aSToby Isaac         PetscInt colOff = 0;
30013b1c2a6aSToby Isaac 
30023b1c2a6aSToby Isaac         for (i = 0; i < numChildren; i++) {
30033b1c2a6aSToby Isaac           PetscInt child = children[i];
30043b1c2a6aSToby Isaac           PetscInt dof, off, j;
30053b1c2a6aSToby Isaac 
30063b1c2a6aSToby Isaac           if (numSecFields) {
30079566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
30089566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
30099371c9d4SSatish Balay           } else {
30109566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(cSection, child, &dof));
30119566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetOffset(cSection, child, &off));
30123b1c2a6aSToby Isaac           }
30133b1c2a6aSToby Isaac 
3014ad540459SPierre Jolivet           for (j = 0; j < dof; j++) matCols[colOff++] = off + j;
30153b1c2a6aSToby Isaac         }
30163b1c2a6aSToby Isaac       }
30178d2f55e7SToby Isaac       if (classId == PETSCFE_CLASSID) {
30188d2f55e7SToby Isaac         PetscFE              fe = (PetscFE)disc;
30198d2f55e7SToby Isaac         PetscInt             fSize;
302059fc6756SToby Isaac         const PetscInt    ***perms;
302159fc6756SToby Isaac         const PetscScalar ***flips;
302259fc6756SToby Isaac         const PetscInt      *pperms;
302359fc6756SToby Isaac 
30249566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &dsp));
30259566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
30269566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
302759fc6756SToby Isaac         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
302852a3aeb4SToby Isaac         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
30298d2f55e7SToby Isaac           PetscQuadrature  q;
303052a3aeb4SToby Isaac           PetscInt         dim, thisNc, numPoints, j, k;
30318d2f55e7SToby Isaac           const PetscReal *points;
30328d2f55e7SToby Isaac           const PetscReal *weights;
30338d2f55e7SToby Isaac           PetscInt        *closure = NULL;
30348d2f55e7SToby Isaac           PetscInt         numClosure;
303559fc6756SToby Isaac           PetscInt         iCell              = pperms ? pperms[i] : i;
303659fc6756SToby Isaac           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3037ef0bb6c7SMatthew G. Knepley           PetscTabulation  Tparent;
30388d2f55e7SToby Isaac 
30399566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
30409566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
304163a3b9bcSJacob Faibussowitsch           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
30429566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
30433b1c2a6aSToby Isaac           for (j = 0; j < numPoints; j++) {
30448d2f55e7SToby Isaac             PetscInt           childCell = -1;
304552a3aeb4SToby Isaac             PetscReal         *parentValAtPoint;
3046c330f8ffSToby Isaac             const PetscReal    xi0[3]    = {-1., -1., -1.};
30478d2f55e7SToby Isaac             const PetscReal   *pointReal = &points[dim * j];
30488d2f55e7SToby Isaac             const PetscScalar *point;
3049ef0bb6c7SMatthew G. Knepley             PetscTabulation    Tchild;
30508d2f55e7SToby Isaac             PetscInt           childCellShapeOff, pointMatOff;
30518d2f55e7SToby Isaac #if defined(PETSC_USE_COMPLEX)
30528d2f55e7SToby Isaac             PetscInt d;
30538d2f55e7SToby Isaac 
3054ad540459SPierre Jolivet             for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d];
30558d2f55e7SToby Isaac             point = pointScalar;
30568d2f55e7SToby Isaac #else
30578d2f55e7SToby Isaac             point = pointReal;
30588d2f55e7SToby Isaac #endif
30598d2f55e7SToby Isaac 
3060ef0bb6c7SMatthew G. Knepley             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];
30613b1c2a6aSToby Isaac 
30623b1c2a6aSToby Isaac             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
30638d2f55e7SToby Isaac               PetscInt  child = children[k];
30648d2f55e7SToby Isaac               PetscInt *star  = NULL;
30658d2f55e7SToby Isaac               PetscInt  numStar, s;
30668d2f55e7SToby Isaac 
30679566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30688d2f55e7SToby Isaac               for (s = numStar - 1; s >= 0; s--) {
30698d2f55e7SToby Isaac                 PetscInt c = star[2 * s];
30708d2f55e7SToby Isaac 
30718d2f55e7SToby Isaac                 if (c < cStart || c >= cEnd) continue;
30729566063dSJacob Faibussowitsch                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
30738d2f55e7SToby Isaac                 if (childCell >= 0) break;
30748d2f55e7SToby Isaac               }
30759566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
30768d2f55e7SToby Isaac               if (childCell >= 0) break;
30778d2f55e7SToby Isaac             }
307808401ef6SPierre Jolivet             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
30799566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
30809566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3081c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3082c330f8ffSToby Isaac             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);
30838d2f55e7SToby Isaac 
30849566063dSJacob Faibussowitsch             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
30859566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
30863b1c2a6aSToby Isaac             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
30871690c2aeSBarry Smith               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_INT_MIN;
30888d2f55e7SToby Isaac               PetscInt        l;
308959fc6756SToby Isaac               const PetscInt *cperms;
30908d2f55e7SToby Isaac 
30919566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(depth, child, &childDepth));
30928d2f55e7SToby Isaac               childDof = depthNumDof[childDepth];
309359fc6756SToby Isaac               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
30948d2f55e7SToby Isaac                 PetscInt point = closure[2 * l];
30958d2f55e7SToby Isaac                 PetscInt pointDepth;
30968d2f55e7SToby Isaac 
30978d2f55e7SToby Isaac                 childO = closure[2 * l + 1];
309859fc6756SToby Isaac                 if (point == child) {
309959fc6756SToby Isaac                   cI = l;
310059fc6756SToby Isaac                   break;
310159fc6756SToby Isaac                 }
31029566063dSJacob Faibussowitsch                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
31038d2f55e7SToby Isaac                 childCellShapeOff += depthNumDof[pointDepth];
31048d2f55e7SToby Isaac               }
31058d2f55e7SToby Isaac               if (l == numClosure) {
31068d2f55e7SToby Isaac                 pointMatOff += childDof;
31078d2f55e7SToby Isaac                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
31088d2f55e7SToby Isaac               }
310959fc6756SToby Isaac               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
31108d2f55e7SToby Isaac               for (l = 0; l < childDof; l++) {
311159fc6756SToby Isaac                 PetscInt   lCell        = cperms ? cperms[l] : l;
311259fc6756SToby Isaac                 PetscInt   childCellDof = childCellShapeOff + lCell;
311352a3aeb4SToby Isaac                 PetscReal *childValAtPoint;
311452a3aeb4SToby Isaac                 PetscReal  val = 0.;
31158d2f55e7SToby Isaac 
3116ef0bb6c7SMatthew G. Knepley                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
3117ad540459SPierre Jolivet                 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];
311852a3aeb4SToby Isaac 
311952a3aeb4SToby Isaac                 pointMat[i * numChildDof + pointMatOff + l] += val;
31208d2f55e7SToby Isaac               }
31218d2f55e7SToby Isaac               pointMatOff += childDof;
31228d2f55e7SToby Isaac             }
31239566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
31249566063dSJacob Faibussowitsch             PetscCall(PetscTabulationDestroy(&Tchild));
31258d2f55e7SToby Isaac           }
31269566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&Tparent));
31278d2f55e7SToby Isaac         }
31289371c9d4SSatish Balay       } else { /* just the volume-weighted averages of the children */
31293b1c2a6aSToby Isaac         PetscReal parentVol;
3130bfaa5bdcSToby Isaac         PetscInt  childCell;
31313b1c2a6aSToby Isaac 
31329566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3133bfaa5bdcSToby Isaac         for (i = 0, childCell = 0; i < numChildren; i++) {
313452a3aeb4SToby Isaac           PetscInt  child = children[i], j;
31353b1c2a6aSToby Isaac           PetscReal childVol;
31363b1c2a6aSToby Isaac 
31373b1c2a6aSToby Isaac           if (child < cStart || child >= cEnd) continue;
31389566063dSJacob Faibussowitsch           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
3139ad540459SPierre Jolivet           for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
3140bfaa5bdcSToby Isaac           childCell++;
31413b1c2a6aSToby Isaac         }
31428d2f55e7SToby Isaac       }
31433b1c2a6aSToby Isaac       /* Insert pointMat into mat */
31449566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
31459566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
31469566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
31478d2f55e7SToby Isaac     }
31488d2f55e7SToby Isaac   }
31499566063dSJacob Faibussowitsch   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
31509566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointScalar, pointRef));
31519566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
31529566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
31538d2f55e7SToby Isaac   *inj = mat;
31543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31558d2f55e7SToby Isaac }
31568d2f55e7SToby Isaac 
DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree,Mat inj,PetscScalar **** childrenMats)3157d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3158d71ae5a4SJacob Faibussowitsch {
3159f30e825dSToby Isaac   PetscDS        ds;
3160f30e825dSToby Isaac   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3161f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3162f30e825dSToby Isaac   PetscSection   refConSec, refSection;
3163f30e825dSToby Isaac 
3164f30e825dSToby Isaac   PetscFunctionBegin;
31659566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
31669566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
31679566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
31689566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
31699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
31709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
31719566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
31729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &rows));
31739566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3174f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3175f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3176f30e825dSToby Isaac 
31779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
31789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
31799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3180f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3181f30e825dSToby Isaac 
31829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3183f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
318452a3aeb4SToby Isaac       PetscInt cDof, cOff, numCols, r;
3185f30e825dSToby Isaac 
3186f30e825dSToby Isaac       if (numFields > 1) {
31879566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
31889566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
31899371c9d4SSatish Balay       } else {
31909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
31919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3192f30e825dSToby Isaac       }
3193f30e825dSToby Isaac 
3194ad540459SPierre Jolivet       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
3195f30e825dSToby Isaac       numCols = 0;
3196f30e825dSToby Isaac       {
3197f30e825dSToby Isaac         PetscInt aDof, aOff, j;
3198f30e825dSToby Isaac 
3199f30e825dSToby Isaac         if (numFields > 1) {
32009566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
32019566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
32029371c9d4SSatish Balay         } else {
32039566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
32049566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3205f30e825dSToby Isaac         }
3206f30e825dSToby Isaac 
3207ad540459SPierre Jolivet         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j;
3208f30e825dSToby Isaac       }
32099566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3210f30e825dSToby Isaac       /* transpose of constraint matrix */
32119566063dSJacob Faibussowitsch       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3212f30e825dSToby Isaac     }
3213f30e825dSToby Isaac   }
3214f30e825dSToby Isaac   *childrenMats = refPointFieldMats;
32159566063dSJacob Faibussowitsch   PetscCall(PetscFree(rows));
32169566063dSJacob Faibussowitsch   PetscCall(PetscFree(cols));
32173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3218f30e825dSToby Isaac }
3219f30e825dSToby Isaac 
DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree,Mat inj,PetscScalar **** childrenMats)3220d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3221d71ae5a4SJacob Faibussowitsch {
3222f30e825dSToby Isaac   PetscDS        ds;
3223f30e825dSToby Isaac   PetscScalar ***refPointFieldMats;
3224f30e825dSToby Isaac   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3225c6154584SToby Isaac   PetscSection   refConSec, refSection;
3226f30e825dSToby Isaac 
3227f30e825dSToby Isaac   PetscFunctionBegin;
3228f30e825dSToby Isaac   refPointFieldMats = *childrenMats;
3229f30e825dSToby Isaac   *childrenMats     = NULL;
32309566063dSJacob Faibussowitsch   PetscCall(DMGetDS(refTree, &ds));
32319566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(refTree, &refSection));
32329566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &numFields));
32339566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
32349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3235f30e825dSToby Isaac   for (p = pRefStart; p < pRefEnd; p++) {
3236f30e825dSToby Isaac     PetscInt parent, pDof, parentDof;
3237f30e825dSToby Isaac 
32389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
32399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
32409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3241f30e825dSToby Isaac     if (!pDof || !parentDof || parent == p) continue;
3242f30e825dSToby Isaac 
3243f30e825dSToby Isaac     for (f = 0; f < numFields; f++) {
3244f30e825dSToby Isaac       PetscInt cDof;
3245f30e825dSToby Isaac 
3246f30e825dSToby Isaac       if (numFields > 1) {
32479566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
32489371c9d4SSatish Balay       } else {
32499566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3250f30e825dSToby Isaac       }
3251f30e825dSToby Isaac 
32529566063dSJacob Faibussowitsch       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3253f30e825dSToby Isaac     }
32549566063dSJacob Faibussowitsch     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3255f30e825dSToby Isaac   }
32569566063dSJacob Faibussowitsch   PetscCall(PetscFree(refPointFieldMats));
32573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3258f30e825dSToby Isaac }
3259f30e825dSToby Isaac 
DMPlexReferenceTreeGetInjector(DM refTree,Mat * injRef)3260d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef)
3261d71ae5a4SJacob Faibussowitsch {
3262ebf164c7SToby Isaac   Mat         cMatRef;
32636148253fSToby Isaac   PetscObject injRefObj;
32648d2f55e7SToby Isaac 
3265154bca37SToby Isaac   PetscFunctionBegin;
32669566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
32679566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3268ebf164c7SToby Isaac   *injRef = (Mat)injRefObj;
3269ebf164c7SToby Isaac   if (!*injRef) {
32709566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
32719566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3272ec92bd66SToby Isaac     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
32739566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3274ebf164c7SToby Isaac   }
32753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32766148253fSToby Isaac }
3277f30e825dSToby Isaac 
DMPlexTransferInjectorTree(DM coarse,DM fine,PetscSF coarseToFine,const PetscInt * childIds,Vec fineVec,PetscInt numFields,PetscInt * offsets,PetscSection * rootMultiSec,PetscSection * multiLeafSec,PetscInt ** gatheredIndices,PetscScalar ** gatheredValues)3278d71ae5a4SJacob Faibussowitsch 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)
3279d71ae5a4SJacob Faibussowitsch {
3280c921d74cSToby Isaac   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3281ebf164c7SToby Isaac   PetscSection    globalCoarse, globalFine;
3282ebf164c7SToby Isaac   PetscSection    localCoarse, localFine, leafIndicesSec;
3283c921d74cSToby Isaac   PetscSection    multiRootSec, rootIndicesSec;
3284c921d74cSToby Isaac   PetscInt       *leafInds, *rootInds = NULL;
3285c921d74cSToby Isaac   const PetscInt *rootDegrees;
3286c921d74cSToby Isaac   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3287ebf164c7SToby Isaac   PetscSF         coarseToFineEmbedded;
3288ebf164c7SToby Isaac 
3289ebf164c7SToby Isaac   PetscFunctionBegin;
32909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
32919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
32929566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
32939566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
32949566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
32959566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
32969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
32978d2f55e7SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
32987e96bdafSToby Isaac     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
32997e96bdafSToby Isaac     const PetscInt *leaves;
33008d2f55e7SToby Isaac 
33019566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
33027e96bdafSToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
33037e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
33049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
33059566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
33068d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
33078d2f55e7SToby Isaac         numPointsWithDofs++;
3308f30e825dSToby Isaac 
33099566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localFine, p, &dof));
33109566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
33118d2f55e7SToby Isaac       }
33128d2f55e7SToby Isaac     }
33139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
33149566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafIndicesSec));
33159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
331632603206SJames Wright     PetscCall(PetscMalloc1((gatheredIndices ? numIndices : (maxDof + 1)), &leafInds));
33179566063dSJacob Faibussowitsch     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
33187e96bdafSToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
33197e96bdafSToby Isaac       p = leaves ? leaves[l] : l;
33209566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
33219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
33228d2f55e7SToby Isaac       if ((dof - cdof) > 0) {
3323f30e825dSToby Isaac         PetscInt     off, gOff;
3324f30e825dSToby Isaac         PetscInt    *pInd;
3325c921d74cSToby Isaac         PetscScalar *pVal = NULL;
3326f30e825dSToby Isaac 
33277e96bdafSToby Isaac         pointsWithDofs[offset++] = l;
3328f30e825dSToby Isaac 
33299566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3330f30e825dSToby Isaac 
3331c921d74cSToby Isaac         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3332c921d74cSToby Isaac         if (gatheredValues) {
3333c921d74cSToby Isaac           PetscInt i;
3334c921d74cSToby Isaac 
3335c921d74cSToby Isaac           pVal = &leafVals[off + 1];
3336c921d74cSToby Isaac           for (i = 0; i < dof; i++) pVal[i] = 0.;
3337c921d74cSToby Isaac         }
33389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3339f30e825dSToby Isaac 
3340f30e825dSToby Isaac         offsets[0] = 0;
3341f30e825dSToby Isaac         if (numFields) {
3342f30e825dSToby Isaac           PetscInt f;
3343f30e825dSToby Isaac 
3344f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3345f30e825dSToby Isaac             PetscInt fDof;
33469566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3347f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
3348f30e825dSToby Isaac           }
33499566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3350367003a6SStefano Zampini         } else {
33519566063dSJacob Faibussowitsch           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3352f30e825dSToby Isaac         }
33539566063dSJacob Faibussowitsch         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
33548d2f55e7SToby Isaac       }
33558d2f55e7SToby Isaac     }
33569566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
33579566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
33588d2f55e7SToby Isaac   }
3359f30e825dSToby Isaac 
33609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
33619566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
33629566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3363f30e825dSToby Isaac 
33646148253fSToby Isaac   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
33656148253fSToby Isaac     MPI_Datatype threeInt;
33666148253fSToby Isaac     PetscMPIInt  rank;
33676148253fSToby Isaac     PetscInt (*parentNodeAndIdCoarse)[3];
33686148253fSToby Isaac     PetscInt (*parentNodeAndIdFine)[3];
33696148253fSToby Isaac     PetscInt           p, nleaves, nleavesToParents;
33706148253fSToby Isaac     PetscSF            pointSF, sfToParents;
33716148253fSToby Isaac     const PetscInt    *ilocal;
33726148253fSToby Isaac     const PetscSFNode *iremote;
33736148253fSToby Isaac     PetscSFNode       *iremoteToParents;
33746148253fSToby Isaac     PetscInt          *ilocalToParents;
33756148253fSToby Isaac 
33769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
33779566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
33789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&threeInt));
33799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
33809566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(coarse, &pointSF));
33819566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
33826148253fSToby Isaac     for (p = pStartC; p < pEndC; p++) {
33836148253fSToby Isaac       PetscInt parent, childId;
33849566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
33856148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][0] = rank;
33866148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
33876148253fSToby Isaac       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
33886148253fSToby Isaac       if (nleaves > 0) {
33896148253fSToby Isaac         PetscInt leaf = -1;
33906148253fSToby Isaac 
33916148253fSToby Isaac         if (ilocal) {
33929566063dSJacob Faibussowitsch           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
33939371c9d4SSatish Balay         } else {
33946148253fSToby Isaac           leaf = p - pStartC;
33956148253fSToby Isaac         }
33966148253fSToby Isaac         if (leaf >= 0) {
33976148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
33986148253fSToby Isaac           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
33996148253fSToby Isaac         }
34006148253fSToby Isaac       }
34016148253fSToby Isaac     }
34026148253fSToby Isaac     for (p = pStartF; p < pEndF; p++) {
34036148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][0] = -1;
34046148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][1] = -1;
34056148253fSToby Isaac       parentNodeAndIdFine[p - pStartF][2] = -1;
34066148253fSToby Isaac     }
34079566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
34089566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
34096148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3410f30e825dSToby Isaac       PetscInt dof;
3411f30e825dSToby Isaac 
34129566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3413f30e825dSToby Isaac       if (dof) {
3414f30e825dSToby Isaac         PetscInt off;
3415f30e825dSToby Isaac 
34169566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3417c921d74cSToby Isaac         if (gatheredIndices) {
3418c921d74cSToby Isaac           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3419c921d74cSToby Isaac         } else if (gatheredValues) {
3420c921d74cSToby Isaac           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3421c921d74cSToby Isaac         }
3422f30e825dSToby Isaac       }
3423ad540459SPierre Jolivet       if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++;
34246148253fSToby Isaac     }
34259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
34269566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
34276148253fSToby Isaac     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
34286148253fSToby Isaac       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
34296148253fSToby Isaac         ilocalToParents[nleavesToParents] = p - pStartF;
34306497c311SBarry Smith         // FIXME PetscCall(PetscMPIIntCast(parentNodeAndIdFine[p - pStartF][0],&iremoteToParents[nleavesToParents].rank));
3431835f2295SStefano Zampini         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p - pStartF][0];
34326148253fSToby Isaac         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
34336148253fSToby Isaac         nleavesToParents++;
34346148253fSToby Isaac       }
34356148253fSToby Isaac     }
34369566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
34379566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
34389566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34396148253fSToby Isaac 
34406148253fSToby Isaac     coarseToFineEmbedded = sfToParents;
34416148253fSToby Isaac 
34429566063dSJacob Faibussowitsch     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
34439566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&threeInt));
34446148253fSToby Isaac   }
3445f30e825dSToby Isaac 
34466148253fSToby Isaac   { /* winnow out coarse points that don't have dofs */
34476148253fSToby Isaac     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
34486148253fSToby Isaac     PetscSF  sfDofsOnly;
34496148253fSToby Isaac 
34506148253fSToby Isaac     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
34519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34529566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3453ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
34546148253fSToby Isaac     }
34559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
34566148253fSToby Isaac     for (p = pStartC, offset = 0; p < pEndC; p++) {
34579566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
34589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3459ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC;
34606148253fSToby Isaac     }
34619566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
34629566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
34639566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
34646148253fSToby Isaac     coarseToFineEmbedded = sfDofsOnly;
34656148253fSToby Isaac   }
3466f30e825dSToby Isaac 
34676148253fSToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
34689566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
34699566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
34709566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
34719566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
347248a46eb9SPierre Jolivet   for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC]));
34739566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(multiRootSec));
34749566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
34759566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3476f30e825dSToby Isaac   { /* distribute the leaf section */
3477f30e825dSToby Isaac     PetscSF   multi, multiInv, indicesSF;
3478f30e825dSToby Isaac     PetscInt *remoteOffsets, numRootIndices;
34798d2f55e7SToby Isaac 
34809566063dSJacob Faibussowitsch     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
34819566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
34829566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
34839566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
34849566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
34859566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&multiInv));
34869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3487c921d74cSToby Isaac     if (gatheredIndices) {
34889566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
34899566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
34909566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3491c921d74cSToby Isaac     }
3492c921d74cSToby Isaac     if (gatheredValues) {
34939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
34949566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
34959566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3496c921d74cSToby Isaac     }
34979566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&indicesSF));
34988d2f55e7SToby Isaac   }
34999566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafIndicesSec));
35009566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafInds));
35019566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafVals));
35029566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3503c921d74cSToby Isaac   *rootMultiSec = multiRootSec;
3504c921d74cSToby Isaac   *multiLeafSec = rootIndicesSec;
3505c921d74cSToby Isaac   if (gatheredIndices) *gatheredIndices = rootInds;
3506c921d74cSToby Isaac   if (gatheredValues) *gatheredValues = rootVals;
35073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3508ebf164c7SToby Isaac }
3509ebf164c7SToby Isaac 
DMPlexComputeInjectorTree(DM coarse,DM fine,PetscSF coarseToFine,PetscInt * childIds,Mat mat)3510d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3511d71ae5a4SJacob Faibussowitsch {
3512ebf164c7SToby Isaac   DM             refTree;
3513c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
3514ebf164c7SToby Isaac   PetscSection   globalCoarse, globalFine;
3515ebf164c7SToby Isaac   PetscSection   localCoarse, localFine;
3516ebf164c7SToby Isaac   PetscSection   cSecRef;
3517277f51e8SBarry Smith   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3518ebf164c7SToby Isaac   Mat            injRef;
3519c921d74cSToby Isaac   PetscInt       numFields, maxDof;
3520ebf164c7SToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3521ebf164c7SToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3522ebf164c7SToby Isaac   PetscLayout    rowMap, colMap;
3523ebf164c7SToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3524ebf164c7SToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
3525ebf164c7SToby Isaac 
3526ebf164c7SToby Isaac   PetscFunctionBegin;
3527ebf164c7SToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
35289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
3529d3a532e9SStefano Zampini   PetscCall(DMCopyDisc(coarse, refTree));
3530d3a532e9SStefano Zampini   PetscCall(DMSetLocalSection(refTree, NULL));
3531d3a532e9SStefano Zampini   PetscCall(DMSetDefaultConstraints(refTree, NULL, NULL, NULL));
35329566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
35339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
35349566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
3535ebf164c7SToby Isaac 
35369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
35379566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
35389566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
35399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
35409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
35419566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
35429566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
35439566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3544ebf164c7SToby Isaac   {
3545ebf164c7SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
35469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3547ebf164c7SToby Isaac   }
3548ebf164c7SToby Isaac 
35499566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));
35508d2f55e7SToby Isaac 
35519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxDof, &parentIndices));
3552f30e825dSToby Isaac 
3553f30e825dSToby Isaac   /* count indices */
35549566063dSJacob Faibussowitsch   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
35559566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
35569566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
35579566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
35589566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
35599566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3560f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3561f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
35628d2f55e7SToby Isaac 
35639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
35649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3565f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
35669566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
35678d2f55e7SToby Isaac 
35688d2f55e7SToby Isaac     rowOffsets[0]  = 0;
3569f30e825dSToby Isaac     offsetsCopy[0] = 0;
35708d2f55e7SToby Isaac     if (numFields) {
35718d2f55e7SToby Isaac       PetscInt f;
35728d2f55e7SToby Isaac 
3573f30e825dSToby Isaac       for (f = 0; f < numFields; f++) {
3574f30e825dSToby Isaac         PetscInt fDof;
35759566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3576f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
35778d2f55e7SToby Isaac       }
35789566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3579367003a6SStefano Zampini     } else {
35809566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3581f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
35828d2f55e7SToby Isaac     }
3583f30e825dSToby Isaac 
35849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
35859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3586f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3587f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3588f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3589f30e825dSToby Isaac       const PetscInt *childIndices;
3590f30e825dSToby Isaac 
35919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
35929566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3593f30e825dSToby Isaac       childId      = rootIndices[offset++];
3594f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3595f30e825dSToby Isaac       numIndices--;
3596f30e825dSToby Isaac 
3597f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3598f30e825dSToby Isaac         PetscInt i;
3599f30e825dSToby Isaac 
3600f30e825dSToby Isaac         for (i = 0; i < numIndices; i++) {
3601f30e825dSToby Isaac           PetscInt colIndex = childIndices[i];
3602f30e825dSToby Isaac           PetscInt rowIndex = parentIndices[i];
3603f30e825dSToby Isaac           if (rowIndex < 0) continue;
360408401ef6SPierre Jolivet           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3605a47f92cbSToby Isaac           if (colIndex >= colStart && colIndex < colEnd) {
3606f30e825dSToby Isaac             nnzD[rowIndex - rowStart] = 1;
36079371c9d4SSatish Balay           } else {
3608f30e825dSToby Isaac             nnzO[rowIndex - rowStart] = 1;
3609f30e825dSToby Isaac           }
3610f30e825dSToby Isaac         }
36119371c9d4SSatish Balay       } else {
3612f30e825dSToby Isaac         PetscInt parentId, f, lim;
3613f30e825dSToby Isaac 
36149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3615f30e825dSToby Isaac 
3616f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3617f30e825dSToby Isaac         offsets[0] = 0;
36188d2f55e7SToby Isaac         if (numFields) {
36198d2f55e7SToby Isaac           PetscInt f;
3620f30e825dSToby Isaac 
36218d2f55e7SToby Isaac           for (f = 0; f < numFields; f++) {
3622f30e825dSToby Isaac             PetscInt fDof;
36239566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3624f30e825dSToby Isaac 
3625f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
36268d2f55e7SToby Isaac           }
36279371c9d4SSatish Balay         } else {
3628f30e825dSToby Isaac           PetscInt cDof;
3629f30e825dSToby Isaac 
36309566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3631f30e825dSToby Isaac           offsets[1] = cDof;
3632f30e825dSToby Isaac         }
3633f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3634f30e825dSToby Isaac           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3635f30e825dSToby Isaac           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3636f30e825dSToby Isaac           PetscInt i, numD = 0, numO = 0;
3637f30e825dSToby Isaac 
3638f30e825dSToby Isaac           for (i = childStart; i < childEnd; i++) {
3639f30e825dSToby Isaac             PetscInt colIndex = childIndices[i];
3640f30e825dSToby Isaac 
3641f30e825dSToby Isaac             if (colIndex < 0) continue;
3642f30e825dSToby Isaac             if (colIndex >= colStart && colIndex < colEnd) {
3643f30e825dSToby Isaac               numD++;
36449371c9d4SSatish Balay             } else {
3645f30e825dSToby Isaac               numO++;
3646f30e825dSToby Isaac             }
3647f30e825dSToby Isaac           }
3648f30e825dSToby Isaac           for (i = parentStart; i < parentEnd; i++) {
3649f30e825dSToby Isaac             PetscInt rowIndex = parentIndices[i];
3650f30e825dSToby Isaac 
3651f30e825dSToby Isaac             if (rowIndex < 0) continue;
3652f30e825dSToby Isaac             nnzD[rowIndex - rowStart] += numD;
3653f30e825dSToby Isaac             nnzO[rowIndex - rowStart] += numO;
36548d2f55e7SToby Isaac           }
36558d2f55e7SToby Isaac         }
36568d2f55e7SToby Isaac       }
3657f30e825dSToby Isaac     }
3658f30e825dSToby Isaac   }
3659f30e825dSToby Isaac   /* preallocate */
36609566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
36619566063dSJacob Faibussowitsch   PetscCall(PetscFree2(nnzD, nnzO));
3662f30e825dSToby Isaac   /* insert values */
36639566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3664f30e825dSToby Isaac   for (p = pStartC; p < pEndC; p++) {
3665f30e825dSToby Isaac     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
3666f30e825dSToby Isaac 
36679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
36689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3669f30e825dSToby Isaac     if ((dof - cdof) <= 0) continue;
36709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
3671f30e825dSToby Isaac 
3672f30e825dSToby Isaac     rowOffsets[0]  = 0;
3673f30e825dSToby Isaac     offsetsCopy[0] = 0;
36748d2f55e7SToby Isaac     if (numFields) {
36758d2f55e7SToby Isaac       PetscInt f;
3676f30e825dSToby Isaac 
36778d2f55e7SToby Isaac       for (f = 0; f < numFields; f++) {
3678f30e825dSToby Isaac         PetscInt fDof;
36799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3680f30e825dSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3681f30e825dSToby Isaac       }
36829566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3683367003a6SStefano Zampini     } else {
36849566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3685f30e825dSToby Isaac       rowOffsets[1] = offsetsCopy[0];
3686f30e825dSToby Isaac     }
3687f30e825dSToby Isaac 
36889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
36899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3690f30e825dSToby Isaac     leafEnd = leafStart + numLeaves;
3691f30e825dSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
3692f30e825dSToby Isaac       PetscInt        numIndices, childId, offset;
3693f30e825dSToby Isaac       const PetscInt *childIndices;
3694f30e825dSToby Isaac 
36959566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
36969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3697f30e825dSToby Isaac       childId      = rootIndices[offset++];
3698f30e825dSToby Isaac       childIndices = &rootIndices[offset];
3699f30e825dSToby Isaac       numIndices--;
3700f30e825dSToby Isaac 
3701f30e825dSToby Isaac       if (childId == -1) { /* equivalent points: scatter */
3702f30e825dSToby Isaac         PetscInt i;
3703f30e825dSToby Isaac 
370448a46eb9SPierre Jolivet         for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES));
37059371c9d4SSatish Balay       } else {
3706f30e825dSToby Isaac         PetscInt parentId, f, lim;
37078d2f55e7SToby Isaac 
37089566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
3709f30e825dSToby Isaac 
3710f30e825dSToby Isaac         lim        = PetscMax(1, numFields);
3711f30e825dSToby Isaac         offsets[0] = 0;
37128d2f55e7SToby Isaac         if (numFields) {
3713f30e825dSToby Isaac           PetscInt f;
37148d2f55e7SToby Isaac 
3715f30e825dSToby Isaac           for (f = 0; f < numFields; f++) {
3716f30e825dSToby Isaac             PetscInt fDof;
37179566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
3718f30e825dSToby Isaac 
3719f30e825dSToby Isaac             offsets[f + 1] = fDof + offsets[f];
37208d2f55e7SToby Isaac           }
37219371c9d4SSatish Balay         } else {
3722f30e825dSToby Isaac           PetscInt cDof;
3723f30e825dSToby Isaac 
37249566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3725f30e825dSToby Isaac           offsets[1] = cDof;
37268d2f55e7SToby Isaac         }
3727f30e825dSToby Isaac         for (f = 0; f < lim; f++) {
3728f30e825dSToby Isaac           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3729f30e825dSToby Isaac           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3730f30e825dSToby Isaac           const PetscInt *colIndices = &childIndices[offsets[f]];
3731f30e825dSToby Isaac 
37329566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
37338d2f55e7SToby Isaac         }
37348d2f55e7SToby Isaac       }
37358d2f55e7SToby Isaac     }
37368d2f55e7SToby Isaac   }
37379566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
37389566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
37399566063dSJacob Faibussowitsch   PetscCall(PetscFree(parentIndices));
37409566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
37419566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootIndices));
37429566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
3743f30e825dSToby Isaac 
37449566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
37459566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
37463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3747154bca37SToby Isaac }
374838fc2455SToby Isaac 
DMPlexTransferVecTree_Interpolate(DM coarse,Vec vecCoarseLocal,DM fine,Vec vecFine,PetscSF coarseToFine,PetscInt * cids,Vec grad,Vec cellGeom)3749d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3750d71ae5a4SJacob Faibussowitsch {
375162095d54SToby Isaac   PetscSF            coarseToFineEmbedded;
375262095d54SToby Isaac   PetscSection       globalCoarse, globalFine;
375362095d54SToby Isaac   PetscSection       localCoarse, localFine;
375462095d54SToby Isaac   PetscSection       aSec, cSec;
375562095d54SToby Isaac   PetscSection       rootValuesSec;
375662095d54SToby Isaac   PetscSection       leafValuesSec;
375762095d54SToby Isaac   PetscScalar       *rootValues, *leafValues;
375862095d54SToby Isaac   IS                 aIS;
375962095d54SToby Isaac   const PetscInt    *anchors;
376062095d54SToby Isaac   Mat                cMat;
376162095d54SToby Isaac   PetscInt           numFields;
3762412e9a14SMatthew G. Knepley   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
376362095d54SToby Isaac   PetscInt           aStart, aEnd, cStart, cEnd;
376462095d54SToby Isaac   PetscInt          *maxChildIds;
376562095d54SToby Isaac   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
37660eb7e1eaSToby Isaac   PetscFV            fv = NULL;
37670eb7e1eaSToby Isaac   PetscInt           dim, numFVcomps = -1, fvField = -1;
37680eb7e1eaSToby Isaac   DM                 cellDM = NULL, gradDM = NULL;
37690eb7e1eaSToby Isaac   const PetscScalar *cellGeomArray = NULL;
37700eb7e1eaSToby Isaac   const PetscScalar *gradArray     = NULL;
377162095d54SToby Isaac 
3772ebf164c7SToby Isaac   PetscFunctionBegin;
37739566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
37749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
37759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
37769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
37779566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
37789566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(coarse, &dim));
377962095d54SToby Isaac   { /* winnow fine points that don't have global dofs out of the sf */
3780e4a60869SToby Isaac     PetscInt        nleaves, l;
3781e4a60869SToby Isaac     const PetscInt *leaves;
378262095d54SToby Isaac     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
378362095d54SToby Isaac 
37849566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3785e4a60869SToby Isaac 
3786e4a60869SToby Isaac     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3787e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3788e4a60869SToby Isaac 
37899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3791ad540459SPierre Jolivet       if ((dof - cdof) > 0) numPointsWithDofs++;
379262095d54SToby Isaac     }
37939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
37944833aeb0SToby Isaac     for (l = 0, offset = 0; l < nleaves; l++) {
3795e4a60869SToby Isaac       PetscInt p = leaves ? leaves[l] : l;
3796e4a60869SToby Isaac 
37979566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
37989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3799ad540459SPierre Jolivet       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
380062095d54SToby Isaac     }
38019566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
38029566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsWithDofs));
380362095d54SToby Isaac   }
380462095d54SToby Isaac   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
38059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
3806ad540459SPierre Jolivet   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
38079566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
38089566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
380962095d54SToby Isaac 
38109566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
38119566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
381262095d54SToby Isaac 
38139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
38149566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(aIS, &anchors));
38159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
381662095d54SToby Isaac 
38179566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
38189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));
381962095d54SToby Isaac 
382062095d54SToby Isaac   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
38219566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
38229566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
38239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
382462095d54SToby Isaac   {
382562095d54SToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
38269566063dSJacob Faibussowitsch     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
382762095d54SToby Isaac   }
38280eb7e1eaSToby Isaac   if (grad) {
38290eb7e1eaSToby Isaac     PetscInt i;
38300eb7e1eaSToby Isaac 
38319566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeom, &cellDM));
38329566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
38339566063dSJacob Faibussowitsch     PetscCall(VecGetDM(grad, &gradDM));
38349566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(grad, &gradArray));
38350eb7e1eaSToby Isaac     for (i = 0; i < PetscMax(1, numFields); i++) {
38360eb7e1eaSToby Isaac       PetscObject  obj;
38370eb7e1eaSToby Isaac       PetscClassId id;
38380eb7e1eaSToby Isaac 
38399566063dSJacob Faibussowitsch       PetscCall(DMGetField(coarse, i, NULL, &obj));
38409566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
38410eb7e1eaSToby Isaac       if (id == PETSCFV_CLASSID) {
38420eb7e1eaSToby Isaac         fv = (PetscFV)obj;
38439566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
38440eb7e1eaSToby Isaac         fvField = i;
38450eb7e1eaSToby Isaac         break;
38460eb7e1eaSToby Isaac       }
38470eb7e1eaSToby Isaac     }
38480eb7e1eaSToby Isaac   }
384962095d54SToby Isaac 
385062095d54SToby Isaac   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
385162095d54SToby Isaac     PetscInt dof;
385262095d54SToby Isaac     PetscInt maxChildId = maxChildIds[p - pStartC];
385362095d54SToby Isaac     PetscInt numValues  = 0;
385462095d54SToby Isaac 
38559566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3856ad540459SPierre Jolivet     if (dof < 0) dof = -(dof + 1);
385762095d54SToby Isaac     offsets[0]    = 0;
385862095d54SToby Isaac     newOffsets[0] = 0;
385962095d54SToby Isaac     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
386062095d54SToby Isaac       PetscInt *closure = NULL, closureSize, cl;
386162095d54SToby Isaac 
38629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
386362095d54SToby Isaac       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
386462095d54SToby Isaac         PetscInt c = closure[2 * cl], clDof;
386562095d54SToby Isaac 
38669566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
386762095d54SToby Isaac         numValues += clDof;
386862095d54SToby Isaac       }
38699566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
38709371c9d4SSatish Balay     } else if (maxChildId == -1) {
38719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
387262095d54SToby Isaac     }
387362095d54SToby Isaac     /* we will pack the column indices with the field offsets */
387478b7adb5SToby Isaac     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
38750eb7e1eaSToby Isaac       /* also send the centroid, and the gradient */
38760eb7e1eaSToby Isaac       numValues += dim * (1 + numFVcomps);
38770eb7e1eaSToby Isaac     }
38789566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
387962095d54SToby Isaac   }
38809566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootValuesSec));
388162095d54SToby Isaac   {
388262095d54SToby Isaac     PetscInt           numRootValues;
388362095d54SToby Isaac     const PetscScalar *coarseArray;
388462095d54SToby Isaac 
38859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
38869566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRootValues, &rootValues));
38879566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
388862095d54SToby Isaac     for (p = pStartC; p < pEndC; p++) {
388962095d54SToby Isaac       PetscInt     numValues;
389062095d54SToby Isaac       PetscInt     pValOff;
389162095d54SToby Isaac       PetscScalar *pVal;
389262095d54SToby Isaac       PetscInt     maxChildId = maxChildIds[p - pStartC];
389362095d54SToby Isaac 
38949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
3895ad540459SPierre Jolivet       if (!numValues) continue;
38969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
3897f4f49eeaSPierre Jolivet       pVal = &rootValues[pValOff];
389862095d54SToby Isaac       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
38990eb7e1eaSToby Isaac         PetscInt closureSize = numValues;
39009566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
39010eb7e1eaSToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
3902193eb951SToby Isaac           PetscFVCellGeom *cg;
39036dd00756SToby Isaac           PetscScalar     *gradVals = NULL;
39040eb7e1eaSToby Isaac           PetscInt         i;
39050eb7e1eaSToby Isaac 
39060eb7e1eaSToby Isaac           pVal += (numValues - dim * (1 + numFVcomps));
39070eb7e1eaSToby Isaac 
39089566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
39090eb7e1eaSToby Isaac           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
39100eb7e1eaSToby Isaac           pVal += dim;
39119566063dSJacob Faibussowitsch           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
39120eb7e1eaSToby Isaac           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
39130eb7e1eaSToby Isaac         }
39149371c9d4SSatish Balay       } else if (maxChildId == -1) {
391578b7adb5SToby Isaac         PetscInt lDof, lOff, i;
391678b7adb5SToby Isaac 
39179566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
39189566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
391978b7adb5SToby Isaac         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
392078b7adb5SToby Isaac       }
392178b7adb5SToby Isaac     }
39229566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
39239566063dSJacob Faibussowitsch     PetscCall(PetscFree(maxChildIds));
392462095d54SToby Isaac   }
392562095d54SToby Isaac   {
392662095d54SToby Isaac     PetscSF   valuesSF;
392762095d54SToby Isaac     PetscInt *remoteOffsetsValues, numLeafValues;
392862095d54SToby Isaac 
39299566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
39309566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
39319566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
39329566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
39339566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsValues));
39349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
39359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
39369566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39379566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
39389566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&valuesSF));
39399566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootValues));
39409566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootValuesSec));
394162095d54SToby Isaac   }
39429566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
394362095d54SToby Isaac   {
394462095d54SToby Isaac     PetscInt       maxDof;
394562095d54SToby Isaac     PetscInt      *rowIndices;
394662095d54SToby Isaac     DM             refTree;
394762095d54SToby Isaac     PetscInt     **refPointFieldN;
394862095d54SToby Isaac     PetscScalar ***refPointFieldMats;
394962095d54SToby Isaac     PetscSection   refConSec, refAnSec;
39500eb7e1eaSToby Isaac     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
395162095d54SToby Isaac     PetscScalar   *pointWork;
395262095d54SToby Isaac 
39539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
39549566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
39559566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
39569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
39579566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(fine, refTree));
39589566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
39599566063dSJacob Faibussowitsch     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
39609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
39619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
39629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
39639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
39640eb7e1eaSToby Isaac     for (p = leafStart; p < leafEnd; p++) {
396562095d54SToby Isaac       PetscInt           gDof, gcDof, gOff, lDof;
396662095d54SToby Isaac       PetscInt           numValues, pValOff;
396762095d54SToby Isaac       PetscInt           childId;
396862095d54SToby Isaac       const PetscScalar *pVal;
39690eb7e1eaSToby Isaac       const PetscScalar *fvGradData = NULL;
397062095d54SToby Isaac 
39719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
39729566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
39739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
3974ad540459SPierre Jolivet       if ((gDof - gcDof) <= 0) continue;
39759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
39769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
397762095d54SToby Isaac       if (!numValues) continue;
39789566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
397962095d54SToby Isaac       pVal              = &leafValues[pValOff];
398062095d54SToby Isaac       offsets[0]        = 0;
398162095d54SToby Isaac       offsetsCopy[0]    = 0;
398262095d54SToby Isaac       newOffsets[0]     = 0;
398362095d54SToby Isaac       newOffsetsCopy[0] = 0;
39844833aeb0SToby Isaac       childId           = cids[p - pStartF];
398562095d54SToby Isaac       if (numFields) {
398662095d54SToby Isaac         PetscInt f;
398762095d54SToby Isaac         for (f = 0; f < numFields; f++) {
398862095d54SToby Isaac           PetscInt rowDof;
398962095d54SToby Isaac 
39909566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
399162095d54SToby Isaac           offsets[f + 1]     = offsets[f] + rowDof;
399262095d54SToby Isaac           offsetsCopy[f + 1] = offsets[f + 1];
399362095d54SToby Isaac           /* TODO: closure indices */
39949f4e70e1SToby Isaac           newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
399562095d54SToby Isaac         }
39969566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
39979371c9d4SSatish Balay       } else {
39984833aeb0SToby Isaac         offsets[0]    = 0;
39994833aeb0SToby Isaac         offsets[1]    = lDof;
40004833aeb0SToby Isaac         newOffsets[0] = 0;
40014833aeb0SToby Isaac         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
40029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
400362095d54SToby Isaac       }
400462095d54SToby Isaac       if (childId == -1) { /* no child interpolation: one nnz per */
40059566063dSJacob Faibussowitsch         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
400662095d54SToby Isaac       } else {
400762095d54SToby Isaac         PetscInt f;
400862095d54SToby Isaac 
400978b7adb5SToby Isaac         if (grad && p >= cellStart && p < cellEnd) {
401078b7adb5SToby Isaac           numValues -= (dim * (1 + numFVcomps));
401178b7adb5SToby Isaac           fvGradData = &pVal[numValues];
401278b7adb5SToby Isaac         }
401362095d54SToby Isaac         for (f = 0; f < PetscMax(1, numFields); f++) {
401462095d54SToby Isaac           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
401562095d54SToby Isaac           PetscInt           numRows  = offsets[f + 1] - offsets[f];
401662095d54SToby Isaac           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
401762095d54SToby Isaac           const PetscScalar *cVal     = &pVal[newOffsets[f]];
401862095d54SToby Isaac           PetscScalar       *rVal     = &pointWork[offsets[f]];
401962095d54SToby Isaac           PetscInt           i, j;
402062095d54SToby Isaac 
4021708c7f19SToby Isaac #if 0
402263a3b9bcSJacob 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));
4023708c7f19SToby Isaac #endif
402462095d54SToby Isaac           for (i = 0; i < numRows; i++) {
402562095d54SToby Isaac             PetscScalar val = 0.;
4026ad540459SPierre Jolivet             for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j];
402762095d54SToby Isaac             rVal[i] = val;
402862095d54SToby Isaac           }
40290eb7e1eaSToby Isaac           if (f == fvField && p >= cellStart && p < cellEnd) {
40300eb7e1eaSToby Isaac             PetscReal          centroid[3];
40310eb7e1eaSToby Isaac             PetscScalar        diff[3];
40320eb7e1eaSToby Isaac             const PetscScalar *parentCentroid = &fvGradData[0];
40330eb7e1eaSToby Isaac             const PetscScalar *gradient       = &fvGradData[dim];
40340eb7e1eaSToby Isaac 
40359566063dSJacob Faibussowitsch             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
4036ad540459SPierre Jolivet             for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i];
40370eb7e1eaSToby Isaac             for (i = 0; i < numFVcomps; i++) {
40380eb7e1eaSToby Isaac               PetscScalar val = 0.;
40390eb7e1eaSToby Isaac 
4040ad540459SPierre Jolivet               for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j];
40410eb7e1eaSToby Isaac               rVal[i] += val;
40420eb7e1eaSToby Isaac             }
40430eb7e1eaSToby Isaac           }
40449566063dSJacob Faibussowitsch           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
404562095d54SToby Isaac         }
404662095d54SToby Isaac       }
404762095d54SToby Isaac     }
40489566063dSJacob Faibussowitsch     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
40499566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
40509566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
405162095d54SToby Isaac   }
40529566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafValues));
40539566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&leafValuesSec));
40549566063dSJacob Faibussowitsch   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
40559566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(aIS, &anchors));
40563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4057ebf164c7SToby Isaac }
4058ebf164c7SToby Isaac 
DMPlexTransferVecTree_Inject(DM fine,Vec vecFine,DM coarse,Vec vecCoarse,PetscSF coarseToFine,PetscInt * cids)4059d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4060d71ae5a4SJacob Faibussowitsch {
4061c921d74cSToby Isaac   DM             refTree;
4062c921d74cSToby Isaac   PetscSection   multiRootSec, rootIndicesSec;
4063c921d74cSToby Isaac   PetscSection   globalCoarse, globalFine;
4064c921d74cSToby Isaac   PetscSection   localCoarse, localFine;
4065c921d74cSToby Isaac   PetscSection   cSecRef;
4066c921d74cSToby Isaac   PetscInt      *parentIndices, pRefStart, pRefEnd;
4067d3bc4906SToby Isaac   PetscScalar   *rootValues, *parentValues;
4068c921d74cSToby Isaac   Mat            injRef;
4069c921d74cSToby Isaac   PetscInt       numFields, maxDof;
4070c921d74cSToby Isaac   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4071c921d74cSToby Isaac   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4072c921d74cSToby Isaac   PetscLayout    rowMap, colMap;
4073c921d74cSToby Isaac   PetscInt       rowStart, rowEnd, colStart, colEnd;
4074c921d74cSToby Isaac   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */
4075c921d74cSToby Isaac 
4076ebf164c7SToby Isaac   PetscFunctionBegin;
4077c921d74cSToby Isaac   /* get the templates for the fine-to-coarse injection from the reference tree */
40789566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40799566063dSJacob Faibussowitsch   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
40809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
40819566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(coarse, refTree));
40829566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
40839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
40849566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));
4085c921d74cSToby Isaac 
40869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
40879566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(fine, &localFine));
40889566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(fine, &globalFine));
40899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
40909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
40919566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(coarse, &localCoarse));
40929566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
40939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4094c921d74cSToby Isaac   {
4095c921d74cSToby Isaac     PetscInt maxFields = PetscMax(1, numFields) + 1;
40969566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4097c921d74cSToby Isaac   }
4098c921d74cSToby Isaac 
40999566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));
4100c921d74cSToby Isaac 
41019566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));
4102c921d74cSToby Isaac 
4103c921d74cSToby Isaac   /* count indices */
41049566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecFine, &colMap));
41059566063dSJacob Faibussowitsch   PetscCall(VecGetLayout(vecCoarse, &rowMap));
41069566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rowMap));
41079566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(colMap));
41089566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
41099566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4110c921d74cSToby Isaac   /* insert values */
41119566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4112c921d74cSToby Isaac   for (p = pStartC; p < pEndC; p++) {
4113c921d74cSToby Isaac     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
411478b7adb5SToby Isaac     PetscBool contribute = PETSC_FALSE;
4115c921d74cSToby Isaac 
41169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
41179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4118c921d74cSToby Isaac     if ((dof - cdof) <= 0) continue;
41199566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
41209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
4121c921d74cSToby Isaac 
4122c921d74cSToby Isaac     rowOffsets[0]  = 0;
4123c921d74cSToby Isaac     offsetsCopy[0] = 0;
4124c921d74cSToby Isaac     if (numFields) {
4125c921d74cSToby Isaac       PetscInt f;
4126c921d74cSToby Isaac 
4127c921d74cSToby Isaac       for (f = 0; f < numFields; f++) {
4128c921d74cSToby Isaac         PetscInt fDof;
41299566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4130c921d74cSToby Isaac         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4131c921d74cSToby Isaac       }
41329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4133367003a6SStefano Zampini     } else {
41349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4135c921d74cSToby Isaac       rowOffsets[1] = offsetsCopy[0];
4136c921d74cSToby Isaac     }
4137c921d74cSToby Isaac 
41389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
41399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4140c921d74cSToby Isaac     leafEnd = leafStart + numLeaves;
41412f65e181SToby Isaac     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4142c921d74cSToby Isaac     for (l = leafStart; l < leafEnd; l++) {
4143c921d74cSToby Isaac       PetscInt           numIndices, childId, offset;
4144c921d74cSToby Isaac       const PetscScalar *childValues;
4145c921d74cSToby Isaac 
41469566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
41479566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4148c921d74cSToby Isaac       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4149c921d74cSToby Isaac       childValues = &rootValues[offset];
4150c921d74cSToby Isaac       numIndices--;
4151c921d74cSToby Isaac 
4152c921d74cSToby Isaac       if (childId == -2) { /* skip */
4153c921d74cSToby Isaac         continue;
4154c921d74cSToby Isaac       } else if (childId == -1) { /* equivalent points: scatter */
41552f65e181SToby Isaac         PetscInt m;
41562f65e181SToby Isaac 
415778b7adb5SToby Isaac         contribute = PETSC_TRUE;
41582f65e181SToby Isaac         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4159beedf8abSToby Isaac       } else { /* contributions from children: sum with injectors from reference tree */
4160d3bc4906SToby Isaac         PetscInt parentId, f, lim;
4161d3bc4906SToby Isaac 
416278b7adb5SToby Isaac         contribute = PETSC_TRUE;
41639566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));
4164d3bc4906SToby Isaac 
4165d3bc4906SToby Isaac         lim        = PetscMax(1, numFields);
4166d3bc4906SToby Isaac         offsets[0] = 0;
4167d3bc4906SToby Isaac         if (numFields) {
4168d3bc4906SToby Isaac           PetscInt f;
4169d3bc4906SToby Isaac 
4170d3bc4906SToby Isaac           for (f = 0; f < numFields; f++) {
4171d3bc4906SToby Isaac             PetscInt fDof;
41729566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));
4173d3bc4906SToby Isaac 
4174d3bc4906SToby Isaac             offsets[f + 1] = fDof + offsets[f];
4175d3bc4906SToby Isaac           }
41769371c9d4SSatish Balay         } else {
4177d3bc4906SToby Isaac           PetscInt cDof;
4178d3bc4906SToby Isaac 
41799566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4180d3bc4906SToby Isaac           offsets[1] = cDof;
4181d3bc4906SToby Isaac         }
4182d3bc4906SToby Isaac         for (f = 0; f < lim; f++) {
4183d3bc4906SToby Isaac           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4184d3bc4906SToby Isaac           PetscInt           n        = offsets[f + 1] - offsets[f];
4185e328ff09SToby Isaac           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4186d3bc4906SToby Isaac           PetscInt           i, j;
4187d3bc4906SToby Isaac           const PetscScalar *colValues = &childValues[offsets[f]];
4188d3bc4906SToby Isaac 
4189e328ff09SToby Isaac           for (i = 0; i < m; i++) {
4190d3bc4906SToby Isaac             PetscScalar val = 0.;
4191ad540459SPierre Jolivet             for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j];
4192e328ff09SToby Isaac             parentValues[rowOffsets[f] + i] += val;
4193d3bc4906SToby Isaac           }
4194d3bc4906SToby Isaac         }
4195c921d74cSToby Isaac       }
4196c921d74cSToby Isaac     }
41979566063dSJacob Faibussowitsch     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4198c921d74cSToby Isaac   }
41999566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&multiRootSec));
42009566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootIndicesSec));
42019566063dSJacob Faibussowitsch   PetscCall(PetscFree2(parentIndices, parentValues));
42029566063dSJacob Faibussowitsch   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
42039566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootValues));
42049566063dSJacob Faibussowitsch   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
42053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4206ebf164c7SToby Isaac }
4207ebf164c7SToby Isaac 
4208ff1f73f7SToby Isaac /*@
4209ff1f73f7SToby Isaac   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4210ff1f73f7SToby Isaac   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4211ff1f73f7SToby Isaac   coarsening and refinement at the same time.
4212ff1f73f7SToby Isaac 
421320f4b53cSBarry Smith   Collective
4214ff1f73f7SToby Isaac 
4215ff1f73f7SToby Isaac   Input Parameters:
4216a1cb98faSBarry Smith + dmIn        - The `DMPLEX` mesh for the input vector
421720f4b53cSBarry Smith . dmOut       - The second `DMPLEX` mesh
4218ff1f73f7SToby Isaac . vecIn       - The input vector
421920f4b53cSBarry Smith . sfRefine    - A star forest indicating points in the mesh `dmIn` (roots in the star forest) that are parents to points in
422020f4b53cSBarry Smith                 the mesh `dmOut` (leaves in the star forest), i.e. where `dmOut` is more refined than `dmIn`
422120f4b53cSBarry Smith . sfCoarsen   - A star forest indicating points in the mesh `dmOut` (roots in the star forest) that are parents to points in
422220f4b53cSBarry Smith                 the mesh `dmIn` (leaves in the star forest), i.e. where `dmOut` is more coarsened than `dmIn`
422320f4b53cSBarry Smith . cidsRefine  - The childIds of the points in `dmOut`.  These childIds relate back to the reference tree: childid[j] = k implies
422420f4b53cSBarry Smith                 that mesh point j of `dmOut` was refined from a point in `dmIn` just as the mesh point k in the reference
422520f4b53cSBarry Smith                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in `dmOut` is exactly
422620f4b53cSBarry Smith                 equivalent to its root in `dmIn`, so no interpolation is necessary.  childid[j] = -2 indicates that this
422720f4b53cSBarry Smith                 point j in `dmOut` is not a leaf of `sfRefine`.
422820f4b53cSBarry Smith . cidsCoarsen - The childIds of the points in `dmIn`.  These childIds relate back to the reference tree: childid[j] = k implies
422920f4b53cSBarry Smith                 that mesh point j of dmIn coarsens to a point in `dmOut` just as the mesh point k in the reference
423020f4b53cSBarry Smith                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in `dmOut` is not a leaf in `sfCoarsen`.
423120f4b53cSBarry Smith . useBCs      - `PETSC_TRUE` indicates that boundary values should be inserted into `vecIn` before transfer.
4232ff1f73f7SToby Isaac - time        - Used if boundary values are time dependent.
4233ff1f73f7SToby Isaac 
42342fe279fdSBarry Smith   Output Parameter:
42358966356dSPierre Jolivet . vecOut - Using interpolation and injection operators calculated on the reference tree, the transferred
423620f4b53cSBarry Smith                 projection of `vecIn` from `dmIn` to `dmOut`.  Note that any field discretized with a `PetscFV` finite volume
4237ff1f73f7SToby Isaac                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4238ff1f73f7SToby Isaac                 coarse points to fine points.
4239ff1f73f7SToby Isaac 
4240ff1f73f7SToby Isaac   Level: developer
4241ff1f73f7SToby Isaac 
42421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4243ff1f73f7SToby Isaac @*/
DMPlexTransferVecTree(DM dmIn,Vec vecIn,DM dmOut,Vec vecOut,PetscSF sfRefine,PetscSF sfCoarsen,PetscInt * cidsRefine,PetscInt * cidsCoarsen,PetscBool useBCs,PetscReal time)4244d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4245d71ae5a4SJacob Faibussowitsch {
424638fc2455SToby Isaac   PetscFunctionBegin;
42479566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
4248ff1f73f7SToby Isaac   if (sfRefine) {
4249fbfa57b9SToby Isaac     Vec vecInLocal;
42500eb7e1eaSToby Isaac     DM  dmGrad   = NULL;
42510eb7e1eaSToby Isaac     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4252fbfa57b9SToby Isaac 
42539566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
42549566063dSJacob Faibussowitsch     PetscCall(VecSet(vecInLocal, 0.0));
42550eb7e1eaSToby Isaac     {
42560eb7e1eaSToby Isaac       PetscInt numFields, i;
42570eb7e1eaSToby Isaac 
42589566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dmIn, &numFields));
42590eb7e1eaSToby Isaac       for (i = 0; i < numFields; i++) {
42600eb7e1eaSToby Isaac         PetscObject  obj;
42610eb7e1eaSToby Isaac         PetscClassId classid;
42620eb7e1eaSToby Isaac 
42639566063dSJacob Faibussowitsch         PetscCall(DMGetField(dmIn, i, NULL, &obj));
42649566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &classid));
42650eb7e1eaSToby Isaac         if (classid == PETSCFV_CLASSID) {
42669566063dSJacob Faibussowitsch           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
42670eb7e1eaSToby Isaac           break;
42680eb7e1eaSToby Isaac         }
42690eb7e1eaSToby Isaac       }
42700eb7e1eaSToby Isaac     }
42711baa6e33SBarry Smith     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
42729566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42739566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
42740eb7e1eaSToby Isaac     if (dmGrad) {
42759566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
42769566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
42770eb7e1eaSToby Isaac     }
42789566063dSJacob Faibussowitsch     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
42799566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
428048a46eb9SPierre Jolivet     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4281ebf164c7SToby Isaac   }
42821baa6e33SBarry Smith   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
42839566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(vecOut));
42849566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(vecOut));
42853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
428638fc2455SToby Isaac }
4287