Actual source code: plextree.c

  1: #include <petsc/private/dmpleximpl.h>
  2: #include <petsc/private/isimpl.h>
  3: #include <petsc/private/petscfeimpl.h>
  4: #include <petscsf.h>
  5: #include <petscds.h>

  7: /* hierarchy routines */

  9: /*@
 10:   DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes.

 12:   Not Collective

 14:   Input Parameters:
 15: + dm - The `DMPLEX` object
 16: - ref - The reference tree `DMPLEX` object

 18:   Level: intermediate

 20: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`,`DMPlexGetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
 21: @*/
 22: PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref)
 23: {
 24:   DM_Plex *mesh = (DM_Plex *)dm->data;

 26:   PetscFunctionBegin;
 29:   PetscCall(PetscObjectReference((PetscObject)ref));
 30:   PetscCall(DMDestroy(&mesh->referenceTree));
 31:   mesh->referenceTree = ref;
 32:   PetscFunctionReturn(PETSC_SUCCESS);
 33: }

 35: /*@
 36:   DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes.

 38:   Not Collective

 40:   Input Parameter:
 41: . dm - The `DMPLEX` object

 43:   Output Parameter:
 44: . ref - The reference tree `DMPLEX` object

 46:   Level: intermediate

 48: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()`
 49: @*/
 50: PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref)
 51: {
 52:   DM_Plex *mesh = (DM_Plex *)dm->data;

 54:   PetscFunctionBegin;
 57:   *ref = mesh->referenceTree;
 58:   PetscFunctionReturn(PETSC_SUCCESS);
 59: }

 61: static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
 62: {
 63:   PetscInt coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert;

 65:   PetscFunctionBegin;
 66:   if (parentOrientA == parentOrientB) {
 67:     if (childOrientB) *childOrientB = childOrientA;
 68:     if (childB) *childB = childA;
 69:     PetscFunctionReturn(PETSC_SUCCESS);
 70:   }
 71:   for (dim = 0; dim < 3; dim++) {
 72:     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
 73:     if (parent >= dStart && parent <= dEnd) break;
 74:   }
 75:   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
 76:   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
 77:   if (childA < dStart || childA >= dEnd) {
 78:     /* this is a lower-dimensional child: bootstrap */
 79:     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
 80:     const PetscInt *supp, *coneA, *coneB, *oA, *oB;

 82:     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
 83:     PetscCall(DMPlexGetSupport(dm, childA, &supp));

 85:     /* find a point sA in supp(childA) that has the same parent */
 86:     for (i = 0; i < size; i++) {
 87:       PetscInt sParent;

 89:       sA = supp[i];
 90:       if (sA == parent) continue;
 91:       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
 92:       if (sParent == parent) break;
 93:     }
 94:     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
 95:     /* find out which point sB is in an equivalent position to sA under
 96:      * parentOrientB */
 97:     PetscCall(DMPlexReferenceTreeGetChildSymmetry_Default(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
 98:     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
 99:     PetscCall(DMPlexGetCone(dm, sA, &coneA));
100:     PetscCall(DMPlexGetCone(dm, sB, &coneB));
101:     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
102:     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
103:     /* step through the cone of sA in natural order */
104:     for (i = 0; i < sConeSize; i++) {
105:       if (coneA[i] == childA) {
106:         /* if childA is at position i in coneA,
107:          * then we want the point that is at sOrientB*i in coneB */
108:         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
109:         if (childB) *childB = coneB[j];
110:         if (childOrientB) {
111:           DMPolytopeType ct;
112:           PetscInt       oBtrue;

114:           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
115:           /* compose sOrientB and oB[j] */
116:           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
117:           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
118:           /* we may have to flip an edge */
119:           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]);
120:           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
121:           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
122:           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
123:         }
124:         break;
125:       }
126:     }
127:     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
128:     PetscFunctionReturn(PETSC_SUCCESS);
129:   }
130:   /* get the cone size and symmetry swap */
131:   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
132:   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
133:   if (dim == 2) {
134:     /* orientations refer to cones: we want them to refer to vertices:
135:      * if it's a rotation, they are the same, but if the order is reversed, a
136:      * permutation that puts side i first does *not* put vertex i first */
137:     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
138:     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
139:     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
140:   } else {
141:     ABswapVert = ABswap;
142:   }
143:   if (childB) {
144:     /* assume that each child corresponds to a vertex, in the same order */
145:     PetscInt        p, posA = -1, numChildren, i;
146:     const PetscInt *children;

148:     /* count which position the child is in */
149:     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
150:     for (i = 0; i < numChildren; i++) {
151:       p = children[i];
152:       if (p == childA) {
153:         posA = i;
154:         break;
155:       }
156:     }
157:     if (posA >= coneSize) {
158:       /* this is the triangle in the middle of a uniformly refined triangle: it
159:        * is invariant */
160:       PetscCheck(dim == 2 && posA == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected a middle triangle, got something else");
161:       *childB = childA;
162:     } else {
163:       /* figure out position B by applying ABswapVert */
164:       PetscInt posB;

166:       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize);
167:       if (childB) *childB = children[posB];
168:     }
169:   }
170:   if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
171:   PetscFunctionReturn(PETSC_SUCCESS);
172: }

174: /*@
175:   DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another

177:   Input Parameters:
178: + dm - the reference tree `DMPLEX` object
179: . parent - the parent point
180: . parentOrientA - the reference orientation for describing the parent
181: . childOrientA - the reference orientation for describing the child
182: . childA - the reference childID for describing the child
183: - parentOrientB - the new orientation for describing the parent

185:   Output Parameters:
186: + childOrientB - if not `NULL`, set to the new orientation for describing the child
187: - childB - if not `NULL`, the new childID for describing the child

189:   Level: developer

191: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetReferenceTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetTree()`
192: @*/
193: PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
194: {
195:   DM_Plex *mesh = (DM_Plex *)dm->data;

197:   PetscFunctionBegin;
199:   PetscCheck(mesh->getchildsymmetry, PETSC_COMM_SELF, PETSC_ERR_SUP, "DMPlexReferenceTreeGetChildSymmetry not implemented");
200:   PetscCall(mesh->getchildsymmetry(dm, parent, parentOrientA, childOrientA, childA, parentOrientB, childOrientB, childB));
201:   PetscFunctionReturn(PETSC_SUCCESS);
202: }

204: static PetscErrorCode DMPlexSetTree_Internal(DM, PetscSection, PetscInt *, PetscInt *, PetscBool, PetscBool);

206: PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
207: {
208:   PetscFunctionBegin;
209:   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_TRUE, PETSC_FALSE));
210:   PetscFunctionReturn(PETSC_SUCCESS);
211: }

213: PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref)
214: {
215:   MPI_Comm     comm;
216:   PetscInt     dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs;
217:   PetscInt    *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts;
218:   DMLabel      identity, identityRef;
219:   PetscSection unionSection, unionConeSection, parentSection;
220:   PetscScalar *unionCoords;
221:   IS           perm;

223:   PetscFunctionBegin;
224:   comm = PetscObjectComm((PetscObject)K);
225:   PetscCall(DMGetDimension(K, &dim));
226:   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
227:   PetscCall(DMGetLabel(K, labelName, &identity));
228:   PetscCall(DMGetLabel(Kref, labelName, &identityRef));
229:   PetscCall(DMPlexGetChart(Kref, &pRefStart, &pRefEnd));
230:   PetscCall(PetscSectionCreate(comm, &unionSection));
231:   PetscCall(PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart)));
232:   /* count points that will go in the union */
233:   for (p = pStart; p < pEnd; p++) PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1));
234:   for (p = pRefStart; p < pRefEnd; p++) {
235:     PetscInt q, qSize;
236:     PetscCall(DMLabelGetValue(identityRef, p, &q));
237:     PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize));
238:     if (qSize > 1) PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1));
239:   }
240:   PetscCall(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart, &permvals));
241:   offset = 0;
242:   /* stratify points in the union by topological dimension */
243:   for (d = 0; d <= dim; d++) {
244:     PetscInt cStart, cEnd, c;

246:     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd));
247:     for (c = cStart; c < cEnd; c++) permvals[offset++] = c;

249:     PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd));
250:     for (c = cStart; c < cEnd; c++) permvals[offset++] = c + (pEnd - pStart);
251:   }
252:   PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm));
253:   PetscCall(PetscSectionSetPermutation(unionSection, perm));
254:   PetscCall(PetscSectionSetUp(unionSection));
255:   PetscCall(PetscSectionGetStorageSize(unionSection, &numUnionPoints));
256:   PetscCall(PetscMalloc2(numUnionPoints, &coneSizes, dim + 1, &numDimPoints));
257:   /* count dimension points */
258:   for (d = 0; d <= dim; d++) {
259:     PetscInt cStart, cOff, cOff2;
260:     PetscCall(DMPlexGetHeightStratum(K, d, &cStart, NULL));
261:     PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff));
262:     if (d < dim) {
263:       PetscCall(DMPlexGetHeightStratum(K, d + 1, &cStart, NULL));
264:       PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff2));
265:     } else {
266:       cOff2 = numUnionPoints;
267:     }
268:     numDimPoints[dim - d] = cOff2 - cOff;
269:   }
270:   PetscCall(PetscSectionCreate(comm, &unionConeSection));
271:   PetscCall(PetscSectionSetChart(unionConeSection, 0, numUnionPoints));
272:   /* count the cones in the union */
273:   for (p = pStart; p < pEnd; p++) {
274:     PetscInt dof, uOff;

276:     PetscCall(DMPlexGetConeSize(K, p, &dof));
277:     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
278:     PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
279:     coneSizes[uOff] = dof;
280:   }
281:   for (p = pRefStart; p < pRefEnd; p++) {
282:     PetscInt dof, uDof, uOff;

284:     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
285:     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
286:     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
287:     if (uDof) {
288:       PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof));
289:       coneSizes[uOff] = dof;
290:     }
291:   }
292:   PetscCall(PetscSectionSetUp(unionConeSection));
293:   PetscCall(PetscSectionGetStorageSize(unionConeSection, &numCones));
294:   PetscCall(PetscMalloc2(numCones, &unionCones, numCones, &unionOrientations));
295:   /* write the cones in the union */
296:   for (p = pStart; p < pEnd; p++) {
297:     PetscInt        dof, uOff, c, cOff;
298:     const PetscInt *cone, *orientation;

300:     PetscCall(DMPlexGetConeSize(K, p, &dof));
301:     PetscCall(DMPlexGetCone(K, p, &cone));
302:     PetscCall(DMPlexGetConeOrientation(K, p, &orientation));
303:     PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff));
304:     PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
305:     for (c = 0; c < dof; c++) {
306:       PetscInt e, eOff;
307:       e = cone[c];
308:       PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
309:       unionCones[cOff + c]        = eOff;
310:       unionOrientations[cOff + c] = orientation[c];
311:     }
312:   }
313:   for (p = pRefStart; p < pRefEnd; p++) {
314:     PetscInt        dof, uDof, uOff, c, cOff;
315:     const PetscInt *cone, *orientation;

317:     PetscCall(DMPlexGetConeSize(Kref, p, &dof));
318:     PetscCall(DMPlexGetCone(Kref, p, &cone));
319:     PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation));
320:     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
321:     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
322:     if (uDof) {
323:       PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff));
324:       for (c = 0; c < dof; c++) {
325:         PetscInt e, eOff, eDof;

327:         e = cone[c];
328:         PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart), &eDof));
329:         if (eDof) {
330:           PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff));
331:         } else {
332:           PetscCall(DMLabelGetValue(identityRef, e, &e));
333:           PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff));
334:         }
335:         unionCones[cOff + c]        = eOff;
336:         unionOrientations[cOff + c] = orientation[c];
337:       }
338:     }
339:   }
340:   /* get the coordinates */
341:   {
342:     PetscInt     vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff;
343:     PetscSection KcoordsSec, KrefCoordsSec;
344:     Vec          KcoordsVec, KrefCoordsVec;
345:     PetscScalar *Kcoords;

347:     PetscCall(DMGetCoordinateSection(K, &KcoordsSec));
348:     PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec));
349:     PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec));
350:     PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec));

352:     numVerts = numDimPoints[0];
353:     PetscCall(PetscMalloc1(numVerts * dim, &unionCoords));
354:     PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd));

356:     offset = 0;
357:     for (v = vStart; v < vEnd; v++) {
358:       PetscCall(PetscSectionGetOffset(unionSection, v - pStart, &vOff));
359:       PetscCall(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords));
360:       for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
361:       offset++;
362:     }
363:     PetscCall(DMPlexGetDepthStratum(Kref, 0, &vRefStart, &vRefEnd));
364:     for (v = vRefStart; v < vRefEnd; v++) {
365:       PetscCall(PetscSectionGetDof(unionSection, v - pRefStart + (pEnd - pStart), &vDof));
366:       PetscCall(PetscSectionGetOffset(unionSection, v - pRefStart + (pEnd - pStart), &vOff));
367:       PetscCall(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords));
368:       if (vDof) {
369:         for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d];
370:         offset++;
371:       }
372:     }
373:   }
374:   PetscCall(DMCreate(comm, ref));
375:   PetscCall(DMSetType(*ref, DMPLEX));
376:   PetscCall(DMSetDimension(*ref, dim));
377:   PetscCall(DMPlexCreateFromDAG(*ref, dim, numDimPoints, coneSizes, unionCones, unionOrientations, unionCoords));
378:   /* set the tree */
379:   PetscCall(PetscSectionCreate(comm, &parentSection));
380:   PetscCall(PetscSectionSetChart(parentSection, 0, numUnionPoints));
381:   for (p = pRefStart; p < pRefEnd; p++) {
382:     PetscInt uDof, uOff;

384:     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
385:     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
386:     if (uDof) PetscCall(PetscSectionSetDof(parentSection, uOff, 1));
387:   }
388:   PetscCall(PetscSectionSetUp(parentSection));
389:   PetscCall(PetscSectionGetStorageSize(parentSection, &parentSize));
390:   PetscCall(PetscMalloc2(parentSize, &parents, parentSize, &childIDs));
391:   for (p = pRefStart; p < pRefEnd; p++) {
392:     PetscInt uDof, uOff;

394:     PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof));
395:     PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff));
396:     if (uDof) {
397:       PetscInt pOff, parent, parentU;
398:       PetscCall(PetscSectionGetOffset(parentSection, uOff, &pOff));
399:       PetscCall(DMLabelGetValue(identityRef, p, &parent));
400:       PetscCall(PetscSectionGetOffset(unionSection, parent - pStart, &parentU));
401:       parents[pOff]  = parentU;
402:       childIDs[pOff] = uOff;
403:     }
404:   }
405:   PetscCall(DMPlexCreateReferenceTree_SetTree(*ref, parentSection, parents, childIDs));
406:   PetscCall(PetscSectionDestroy(&parentSection));
407:   PetscCall(PetscFree2(parents, childIDs));

409:   /* clean up */
410:   PetscCall(PetscSectionDestroy(&unionSection));
411:   PetscCall(PetscSectionDestroy(&unionConeSection));
412:   PetscCall(ISDestroy(&perm));
413:   PetscCall(PetscFree(unionCoords));
414:   PetscCall(PetscFree2(unionCones, unionOrientations));
415:   PetscCall(PetscFree2(coneSizes, numDimPoints));
416:   PetscFunctionReturn(PETSC_SUCCESS);
417: }

419: /*@
420:   DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement.

422:   Collective

424:   Input Parameters:
425: + comm    - the MPI communicator
426: . dim     - the spatial dimension
427: - simplex - Flag for simplex, otherwise use a tensor-product cell

429:   Output Parameter:
430: . ref     - the reference tree `DMPLEX` object

432:   Level: intermediate

434: .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`
435: @*/
436: PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref)
437: {
438:   DM_Plex *mesh;
439:   DM       K, Kref;
440:   PetscInt p, pStart, pEnd;
441:   DMLabel  identity;

443:   PetscFunctionBegin;
444: #if 1
445:   comm = PETSC_COMM_SELF;
446: #endif
447:   /* create a reference element */
448:   PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K));
449:   PetscCall(DMCreateLabel(K, "identity"));
450:   PetscCall(DMGetLabel(K, "identity", &identity));
451:   PetscCall(DMPlexGetChart(K, &pStart, &pEnd));
452:   for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(identity, p, p));
453:   /* refine it */
454:   PetscCall(DMRefine(K, comm, &Kref));

456:   /* the reference tree is the union of these two, without duplicating
457:    * points that appear in both */
458:   PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref));
459:   mesh                   = (DM_Plex *)(*ref)->data;
460:   mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default;
461:   PetscCall(DMDestroy(&K));
462:   PetscCall(DMDestroy(&Kref));
463:   PetscFunctionReturn(PETSC_SUCCESS);
464: }

466: static PetscErrorCode DMPlexTreeSymmetrize(DM dm)
467: {
468:   DM_Plex     *mesh = (DM_Plex *)dm->data;
469:   PetscSection childSec, pSec;
470:   PetscInt     p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT;
471:   PetscInt    *offsets, *children, pStart, pEnd;

473:   PetscFunctionBegin;
475:   PetscCall(PetscSectionDestroy(&mesh->childSection));
476:   PetscCall(PetscFree(mesh->children));
477:   pSec = mesh->parentSection;
478:   if (!pSec) PetscFunctionReturn(PETSC_SUCCESS);
479:   PetscCall(PetscSectionGetStorageSize(pSec, &pSize));
480:   for (p = 0; p < pSize; p++) {
481:     PetscInt par = mesh->parents[p];

483:     parMax = PetscMax(parMax, par + 1);
484:     parMin = PetscMin(parMin, par);
485:   }
486:   if (parMin > parMax) {
487:     parMin = -1;
488:     parMax = -1;
489:   }
490:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)pSec), &childSec));
491:   PetscCall(PetscSectionSetChart(childSec, parMin, parMax));
492:   for (p = 0; p < pSize; p++) {
493:     PetscInt par = mesh->parents[p];

495:     PetscCall(PetscSectionAddDof(childSec, par, 1));
496:   }
497:   PetscCall(PetscSectionSetUp(childSec));
498:   PetscCall(PetscSectionGetStorageSize(childSec, &cSize));
499:   PetscCall(PetscMalloc1(cSize, &children));
500:   PetscCall(PetscCalloc1(parMax - parMin, &offsets));
501:   PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd));
502:   for (p = pStart; p < pEnd; p++) {
503:     PetscInt dof, off, i;

505:     PetscCall(PetscSectionGetDof(pSec, p, &dof));
506:     PetscCall(PetscSectionGetOffset(pSec, p, &off));
507:     for (i = 0; i < dof; i++) {
508:       PetscInt par = mesh->parents[off + i], cOff;

510:       PetscCall(PetscSectionGetOffset(childSec, par, &cOff));
511:       children[cOff + offsets[par - parMin]++] = p;
512:     }
513:   }
514:   mesh->childSection = childSec;
515:   mesh->children     = children;
516:   PetscCall(PetscFree(offsets));
517:   PetscFunctionReturn(PETSC_SUCCESS);
518: }

520: static PetscErrorCode AnchorsFlatten(PetscSection section, IS is, PetscSection *sectionNew, IS *isNew)
521: {
522:   PetscInt        pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL;
523:   const PetscInt *vals;
524:   PetscSection    secNew;
525:   PetscBool       anyNew, globalAnyNew;
526:   PetscBool       compress;

528:   PetscFunctionBegin;
529:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
530:   PetscCall(ISGetLocalSize(is, &size));
531:   PetscCall(ISGetIndices(is, &vals));
532:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secNew));
533:   PetscCall(PetscSectionSetChart(secNew, pStart, pEnd));
534:   for (i = 0; i < size; i++) {
535:     PetscInt dof;

537:     p = vals[i];
538:     if (p < pStart || p >= pEnd) continue;
539:     PetscCall(PetscSectionGetDof(section, p, &dof));
540:     if (dof) break;
541:   }
542:   if (i == size) {
543:     PetscCall(PetscSectionSetUp(secNew));
544:     anyNew   = PETSC_FALSE;
545:     compress = PETSC_FALSE;
546:     sizeNew  = 0;
547:   } else {
548:     anyNew = PETSC_TRUE;
549:     for (p = pStart; p < pEnd; p++) {
550:       PetscInt dof, off;

552:       PetscCall(PetscSectionGetDof(section, p, &dof));
553:       PetscCall(PetscSectionGetOffset(section, p, &off));
554:       for (i = 0; i < dof; i++) {
555:         PetscInt q = vals[off + i], qDof = 0;

557:         if (q >= pStart && q < pEnd) PetscCall(PetscSectionGetDof(section, q, &qDof));
558:         if (qDof) PetscCall(PetscSectionAddDof(secNew, p, qDof));
559:         else PetscCall(PetscSectionAddDof(secNew, p, 1));
560:       }
561:     }
562:     PetscCall(PetscSectionSetUp(secNew));
563:     PetscCall(PetscSectionGetStorageSize(secNew, &sizeNew));
564:     PetscCall(PetscMalloc1(sizeNew, &valsNew));
565:     compress = PETSC_FALSE;
566:     for (p = pStart; p < pEnd; p++) {
567:       PetscInt dof, off, count, offNew, dofNew;

569:       PetscCall(PetscSectionGetDof(section, p, &dof));
570:       PetscCall(PetscSectionGetOffset(section, p, &off));
571:       PetscCall(PetscSectionGetDof(secNew, p, &dofNew));
572:       PetscCall(PetscSectionGetOffset(secNew, p, &offNew));
573:       count = 0;
574:       for (i = 0; i < dof; i++) {
575:         PetscInt q = vals[off + i], qDof = 0, qOff = 0, j;

577:         if (q >= pStart && q < pEnd) {
578:           PetscCall(PetscSectionGetDof(section, q, &qDof));
579:           PetscCall(PetscSectionGetOffset(section, q, &qOff));
580:         }
581:         if (qDof) {
582:           PetscInt oldCount = count;

584:           for (j = 0; j < qDof; j++) {
585:             PetscInt k, r = vals[qOff + j];

587:             for (k = 0; k < oldCount; k++) {
588:               if (valsNew[offNew + k] == r) break;
589:             }
590:             if (k == oldCount) valsNew[offNew + count++] = r;
591:           }
592:         } else {
593:           PetscInt k, oldCount = count;

595:           for (k = 0; k < oldCount; k++) {
596:             if (valsNew[offNew + k] == q) break;
597:           }
598:           if (k == oldCount) valsNew[offNew + count++] = q;
599:         }
600:       }
601:       if (count < dofNew) {
602:         PetscCall(PetscSectionSetDof(secNew, p, count));
603:         compress = PETSC_TRUE;
604:       }
605:     }
606:   }
607:   PetscCall(ISRestoreIndices(is, &vals));
608:   PetscCall(MPIU_Allreduce(&anyNew, &globalAnyNew, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
609:   if (!globalAnyNew) {
610:     PetscCall(PetscSectionDestroy(&secNew));
611:     *sectionNew = NULL;
612:     *isNew      = NULL;
613:   } else {
614:     PetscBool globalCompress;

616:     PetscCall(MPIU_Allreduce(&compress, &globalCompress, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew)));
617:     if (compress) {
618:       PetscSection secComp;
619:       PetscInt    *valsComp = NULL;

621:       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secComp));
622:       PetscCall(PetscSectionSetChart(secComp, pStart, pEnd));
623:       for (p = pStart; p < pEnd; p++) {
624:         PetscInt dof;

626:         PetscCall(PetscSectionGetDof(secNew, p, &dof));
627:         PetscCall(PetscSectionSetDof(secComp, p, dof));
628:       }
629:       PetscCall(PetscSectionSetUp(secComp));
630:       PetscCall(PetscSectionGetStorageSize(secComp, &sizeNew));
631:       PetscCall(PetscMalloc1(sizeNew, &valsComp));
632:       for (p = pStart; p < pEnd; p++) {
633:         PetscInt dof, off, offNew, j;

635:         PetscCall(PetscSectionGetDof(secNew, p, &dof));
636:         PetscCall(PetscSectionGetOffset(secNew, p, &off));
637:         PetscCall(PetscSectionGetOffset(secComp, p, &offNew));
638:         for (j = 0; j < dof; j++) valsComp[offNew + j] = valsNew[off + j];
639:       }
640:       PetscCall(PetscSectionDestroy(&secNew));
641:       secNew = secComp;
642:       PetscCall(PetscFree(valsNew));
643:       valsNew = valsComp;
644:     }
645:     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), sizeNew, valsNew, PETSC_OWN_POINTER, isNew));
646:   }
647:   PetscFunctionReturn(PETSC_SUCCESS);
648: }

650: static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm)
651: {
652:   PetscInt     p, pStart, pEnd, *anchors, size;
653:   PetscInt     aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT;
654:   PetscSection aSec;
655:   DMLabel      canonLabel;
656:   IS           aIS;

658:   PetscFunctionBegin;
660:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
661:   PetscCall(DMGetLabel(dm, "canonical", &canonLabel));
662:   for (p = pStart; p < pEnd; p++) {
663:     PetscInt parent;

665:     if (canonLabel) {
666:       PetscInt canon;

668:       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
669:       if (p != canon) continue;
670:     }
671:     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
672:     if (parent != p) {
673:       aMin = PetscMin(aMin, p);
674:       aMax = PetscMax(aMax, p + 1);
675:     }
676:   }
677:   if (aMin > aMax) {
678:     aMin = -1;
679:     aMax = -1;
680:   }
681:   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &aSec));
682:   PetscCall(PetscSectionSetChart(aSec, aMin, aMax));
683:   for (p = aMin; p < aMax; p++) {
684:     PetscInt parent, ancestor = p;

686:     if (canonLabel) {
687:       PetscInt canon;

689:       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
690:       if (p != canon) continue;
691:     }
692:     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
693:     while (parent != ancestor) {
694:       ancestor = parent;
695:       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
696:     }
697:     if (ancestor != p) {
698:       PetscInt closureSize, *closure = NULL;

700:       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
701:       PetscCall(PetscSectionSetDof(aSec, p, closureSize));
702:       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
703:     }
704:   }
705:   PetscCall(PetscSectionSetUp(aSec));
706:   PetscCall(PetscSectionGetStorageSize(aSec, &size));
707:   PetscCall(PetscMalloc1(size, &anchors));
708:   for (p = aMin; p < aMax; p++) {
709:     PetscInt parent, ancestor = p;

711:     if (canonLabel) {
712:       PetscInt canon;

714:       PetscCall(DMLabelGetValue(canonLabel, p, &canon));
715:       if (p != canon) continue;
716:     }
717:     PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL));
718:     while (parent != ancestor) {
719:       ancestor = parent;
720:       PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL));
721:     }
722:     if (ancestor != p) {
723:       PetscInt j, closureSize, *closure = NULL, aOff;

725:       PetscCall(PetscSectionGetOffset(aSec, p, &aOff));

727:       PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
728:       for (j = 0; j < closureSize; j++) anchors[aOff + j] = closure[2 * j];
729:       PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure));
730:     }
731:   }
732:   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, anchors, PETSC_OWN_POINTER, &aIS));
733:   {
734:     PetscSection aSecNew = aSec;
735:     IS           aISNew  = aIS;

737:     PetscCall(PetscObjectReference((PetscObject)aSec));
738:     PetscCall(PetscObjectReference((PetscObject)aIS));
739:     while (aSecNew) {
740:       PetscCall(PetscSectionDestroy(&aSec));
741:       PetscCall(ISDestroy(&aIS));
742:       aSec    = aSecNew;
743:       aIS     = aISNew;
744:       aSecNew = NULL;
745:       aISNew  = NULL;
746:       PetscCall(AnchorsFlatten(aSec, aIS, &aSecNew, &aISNew));
747:     }
748:   }
749:   PetscCall(DMPlexSetAnchors(dm, aSec, aIS));
750:   PetscCall(PetscSectionDestroy(&aSec));
751:   PetscCall(ISDestroy(&aIS));
752:   PetscFunctionReturn(PETSC_SUCCESS);
753: }

755: static PetscErrorCode DMPlexGetTrueSupportSize(DM dm, PetscInt p, PetscInt *dof, PetscInt *numTrueSupp)
756: {
757:   PetscFunctionBegin;
758:   if (numTrueSupp[p] == -1) {
759:     PetscInt        i, alldof;
760:     const PetscInt *supp;
761:     PetscInt        count = 0;

763:     PetscCall(DMPlexGetSupportSize(dm, p, &alldof));
764:     PetscCall(DMPlexGetSupport(dm, p, &supp));
765:     for (i = 0; i < alldof; i++) {
766:       PetscInt        q = supp[i], numCones, j;
767:       const PetscInt *cone;

769:       PetscCall(DMPlexGetConeSize(dm, q, &numCones));
770:       PetscCall(DMPlexGetCone(dm, q, &cone));
771:       for (j = 0; j < numCones; j++) {
772:         if (cone[j] == p) break;
773:       }
774:       if (j < numCones) count++;
775:     }
776:     numTrueSupp[p] = count;
777:   }
778:   *dof = numTrueSupp[p];
779:   PetscFunctionReturn(PETSC_SUCCESS);
780: }

782: static PetscErrorCode DMPlexTreeExchangeSupports(DM dm)
783: {
784:   DM_Plex     *mesh = (DM_Plex *)dm->data;
785:   PetscSection newSupportSection;
786:   PetscInt     newSize, *newSupports, pStart, pEnd, p, d, depth;
787:   PetscInt    *numTrueSupp;
788:   PetscInt    *offsets;

790:   PetscFunctionBegin;
792:   /* symmetrize the hierarchy */
793:   PetscCall(DMPlexGetDepth(dm, &depth));
794:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)), &newSupportSection));
795:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
796:   PetscCall(PetscSectionSetChart(newSupportSection, pStart, pEnd));
797:   PetscCall(PetscCalloc1(pEnd, &offsets));
798:   PetscCall(PetscMalloc1(pEnd, &numTrueSupp));
799:   for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1;
800:   /* if a point is in the (true) support of q, it should be in the support of
801:    * parent(q) */
802:   for (d = 0; d <= depth; d++) {
803:     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
804:     for (p = pStart; p < pEnd; ++p) {
805:       PetscInt dof, q, qdof, parent;

807:       PetscCall(DMPlexGetTrueSupportSize(dm, p, &dof, numTrueSupp));
808:       PetscCall(PetscSectionAddDof(newSupportSection, p, dof));
809:       q = p;
810:       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
811:       while (parent != q && parent >= pStart && parent < pEnd) {
812:         q = parent;

814:         PetscCall(DMPlexGetTrueSupportSize(dm, q, &qdof, numTrueSupp));
815:         PetscCall(PetscSectionAddDof(newSupportSection, p, qdof));
816:         PetscCall(PetscSectionAddDof(newSupportSection, q, dof));
817:         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
818:       }
819:     }
820:   }
821:   PetscCall(PetscSectionSetUp(newSupportSection));
822:   PetscCall(PetscSectionGetStorageSize(newSupportSection, &newSize));
823:   PetscCall(PetscMalloc1(newSize, &newSupports));
824:   for (d = 0; d <= depth; d++) {
825:     PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd));
826:     for (p = pStart; p < pEnd; p++) {
827:       PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent;

829:       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
830:       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
831:       PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof));
832:       PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff));
833:       for (i = 0; i < dof; i++) {
834:         PetscInt        numCones, j;
835:         const PetscInt *cone;
836:         PetscInt        q = mesh->supports[off + i];

838:         PetscCall(DMPlexGetConeSize(dm, q, &numCones));
839:         PetscCall(DMPlexGetCone(dm, q, &cone));
840:         for (j = 0; j < numCones; j++) {
841:           if (cone[j] == p) break;
842:         }
843:         if (j < numCones) newSupports[newOff + offsets[p]++] = q;
844:       }

846:       q = p;
847:       PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
848:       while (parent != q && parent >= pStart && parent < pEnd) {
849:         q = parent;
850:         PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof));
851:         PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff));
852:         PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff));
853:         for (i = 0; i < qdof; i++) {
854:           PetscInt        numCones, j;
855:           const PetscInt *cone;
856:           PetscInt        r = mesh->supports[qoff + i];

858:           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
859:           PetscCall(DMPlexGetCone(dm, r, &cone));
860:           for (j = 0; j < numCones; j++) {
861:             if (cone[j] == q) break;
862:           }
863:           if (j < numCones) newSupports[newOff + offsets[p]++] = r;
864:         }
865:         for (i = 0; i < dof; i++) {
866:           PetscInt        numCones, j;
867:           const PetscInt *cone;
868:           PetscInt        r = mesh->supports[off + i];

870:           PetscCall(DMPlexGetConeSize(dm, r, &numCones));
871:           PetscCall(DMPlexGetCone(dm, r, &cone));
872:           for (j = 0; j < numCones; j++) {
873:             if (cone[j] == p) break;
874:           }
875:           if (j < numCones) newSupports[newqOff + offsets[q]++] = r;
876:         }
877:         PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL));
878:       }
879:     }
880:   }
881:   PetscCall(PetscSectionDestroy(&mesh->supportSection));
882:   mesh->supportSection = newSupportSection;
883:   PetscCall(PetscFree(mesh->supports));
884:   mesh->supports = newSupports;
885:   PetscCall(PetscFree(offsets));
886:   PetscCall(PetscFree(numTrueSupp));

888:   PetscFunctionReturn(PETSC_SUCCESS);
889: }

891: static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM, PetscSection, PetscSection, Mat);
892: static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM, PetscSection, PetscSection, Mat);

894: static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports)
895: {
896:   DM_Plex *mesh = (DM_Plex *)dm->data;
897:   DM       refTree;
898:   PetscInt size;

900:   PetscFunctionBegin;
903:   PetscCall(PetscObjectReference((PetscObject)parentSection));
904:   PetscCall(PetscSectionDestroy(&mesh->parentSection));
905:   mesh->parentSection = parentSection;
906:   PetscCall(PetscSectionGetStorageSize(parentSection, &size));
907:   if (parents != mesh->parents) {
908:     PetscCall(PetscFree(mesh->parents));
909:     PetscCall(PetscMalloc1(size, &mesh->parents));
910:     PetscCall(PetscArraycpy(mesh->parents, parents, size));
911:   }
912:   if (childIDs != mesh->childIDs) {
913:     PetscCall(PetscFree(mesh->childIDs));
914:     PetscCall(PetscMalloc1(size, &mesh->childIDs));
915:     PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size));
916:   }
917:   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
918:   if (refTree) {
919:     DMLabel canonLabel;

921:     PetscCall(DMGetLabel(refTree, "canonical", &canonLabel));
922:     if (canonLabel) {
923:       PetscInt i;

925:       for (i = 0; i < size; i++) {
926:         PetscInt canon;
927:         PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon));
928:         if (canon >= 0) mesh->childIDs[i] = canon;
929:       }
930:     }
931:     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference;
932:   } else {
933:     mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct;
934:   }
935:   PetscCall(DMPlexTreeSymmetrize(dm));
936:   if (computeCanonical) {
937:     PetscInt d, dim;

939:     /* add the canonical label */
940:     PetscCall(DMGetDimension(dm, &dim));
941:     PetscCall(DMCreateLabel(dm, "canonical"));
942:     for (d = 0; d <= dim; d++) {
943:       PetscInt        p, dStart, dEnd, canon = -1, cNumChildren;
944:       const PetscInt *cChildren;

946:       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
947:       for (p = dStart; p < dEnd; p++) {
948:         PetscCall(DMPlexGetTreeChildren(dm, p, &cNumChildren, &cChildren));
949:         if (cNumChildren) {
950:           canon = p;
951:           break;
952:         }
953:       }
954:       if (canon == -1) continue;
955:       for (p = dStart; p < dEnd; p++) {
956:         PetscInt        numChildren, i;
957:         const PetscInt *children;

959:         PetscCall(DMPlexGetTreeChildren(dm, p, &numChildren, &children));
960:         if (numChildren) {
961:           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);
962:           PetscCall(DMSetLabelValue(dm, "canonical", p, canon));
963:           for (i = 0; i < numChildren; i++) PetscCall(DMSetLabelValue(dm, "canonical", children[i], cChildren[i]));
964:         }
965:       }
966:     }
967:   }
968:   if (exchangeSupports) PetscCall(DMPlexTreeExchangeSupports(dm));
969:   mesh->createanchors = DMPlexCreateAnchors_Tree;
970:   /* reset anchors */
971:   PetscCall(DMPlexSetAnchors(dm, NULL, NULL));
972:   PetscFunctionReturn(PETSC_SUCCESS);
973: }

975: /*@
976:   DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points.  This routine also creates
977:   the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its
978:   tree root.

980:   Collective

982:   Input Parameters:
983: + dm - the `DMPLEX` object
984: . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
985:                   offset indexes the parent and childID list; the reference count of parentSection is incremented
986: . parents - a list of the point parents; copied, can be destroyed
987: - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
988:              the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed

990:   Level: intermediate

992: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
993: @*/
994: PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[])
995: {
996:   PetscFunctionBegin;
997:   PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_FALSE, PETSC_TRUE));
998:   PetscFunctionReturn(PETSC_SUCCESS);
999: }

1001: /*@
1002:   DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points.
1003:   Collective

1005:   Input Parameter:
1006: . dm - the `DMPLEX` object

1008:   Output Parameters:
1009: + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section
1010:                   offset indexes the parent and childID list
1011: . parents - a list of the point parents
1012: . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then
1013:              the child corresponds to the point in the reference tree with index childID
1014: . childSection - the inverse of the parent section
1015: - children - a list of the point children

1017:   Level: intermediate

1019: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`,`DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()`
1020: @*/
1021: PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[])
1022: {
1023:   DM_Plex *mesh = (DM_Plex *)dm->data;

1025:   PetscFunctionBegin;
1027:   if (parentSection) *parentSection = mesh->parentSection;
1028:   if (parents) *parents = mesh->parents;
1029:   if (childIDs) *childIDs = mesh->childIDs;
1030:   if (childSection) *childSection = mesh->childSection;
1031:   if (children) *children = mesh->children;
1032:   PetscFunctionReturn(PETSC_SUCCESS);
1033: }

1035: /*@
1036:   DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG)

1038:   Input Parameters:
1039: + dm - the `DMPLEX` object
1040: - point - the query point

1042:   Output Parameters:
1043: + parent - if not `NULL`, set to the parent of the point, or the point itself if the point does not have a parent
1044: - childID - if not `NULL`, set to the child ID of the point with respect to its parent, or 0 if the point
1045:             does not have a parent

1047:   Level: intermediate

1049: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()`
1050: @*/
1051: PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID)
1052: {
1053:   DM_Plex     *mesh = (DM_Plex *)dm->data;
1054:   PetscSection pSec;

1056:   PetscFunctionBegin;
1058:   pSec = mesh->parentSection;
1059:   if (pSec && point >= pSec->pStart && point < pSec->pEnd) {
1060:     PetscInt dof;

1062:     PetscCall(PetscSectionGetDof(pSec, point, &dof));
1063:     if (dof) {
1064:       PetscInt off;

1066:       PetscCall(PetscSectionGetOffset(pSec, point, &off));
1067:       if (parent) *parent = mesh->parents[off];
1068:       if (childID) *childID = mesh->childIDs[off];
1069:       PetscFunctionReturn(PETSC_SUCCESS);
1070:     }
1071:   }
1072:   if (parent) *parent = point;
1073:   if (childID) *childID = 0;
1074:   PetscFunctionReturn(PETSC_SUCCESS);
1075: }

1077: /*@C
1078:   DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG)

1080:   Input Parameters:
1081: + dm - the `DMPLEX` object
1082: - point - the query point

1084:   Output Parameters:
1085: + numChildren - if not `NULL`, set to the number of children
1086: - children - if not `NULL`, set to a list children, or set to `NULL` if the point has no children

1088:   Level: intermediate

1090: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()`
1091: @*/
1092: PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[])
1093: {
1094:   DM_Plex     *mesh = (DM_Plex *)dm->data;
1095:   PetscSection childSec;
1096:   PetscInt     dof = 0;

1098:   PetscFunctionBegin;
1100:   childSec = mesh->childSection;
1101:   if (childSec && point >= childSec->pStart && point < childSec->pEnd) PetscCall(PetscSectionGetDof(childSec, point, &dof));
1102:   if (numChildren) *numChildren = dof;
1103:   if (children) {
1104:     if (dof) {
1105:       PetscInt off;

1107:       PetscCall(PetscSectionGetOffset(childSec, point, &off));
1108:       *children = &mesh->children[off];
1109:     } else {
1110:       *children = NULL;
1111:     }
1112:   }
1113:   PetscFunctionReturn(PETSC_SUCCESS);
1114: }

1116: 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)
1117: {
1118:   PetscInt f, b, p, c, offset, qPoints;

1120:   PetscFunctionBegin;
1121:   PetscCall(PetscSpaceEvaluate(space, nPoints, points, work, NULL, NULL));
1122:   for (f = 0, offset = 0; f < nFunctionals; f++) {
1123:     qPoints = pointsPerFn[f];
1124:     for (b = 0; b < nBasis; b++) {
1125:       PetscScalar val = 0.;

1127:       for (p = 0; p < qPoints; p++) {
1128:         for (c = 0; c < nComps; c++) val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c];
1129:       }
1130:       PetscCall(MatSetValue(basisAtPoints, b, f, val, INSERT_VALUES));
1131:     }
1132:     offset += qPoints;
1133:   }
1134:   PetscCall(MatAssemblyBegin(basisAtPoints, MAT_FINAL_ASSEMBLY));
1135:   PetscCall(MatAssemblyEnd(basisAtPoints, MAT_FINAL_ASSEMBLY));
1136:   PetscFunctionReturn(PETSC_SUCCESS);
1137: }

1139: static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat)
1140: {
1141:   PetscDS         ds;
1142:   PetscInt        spdim;
1143:   PetscInt        numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd;
1144:   const PetscInt *anchors;
1145:   PetscSection    aSec;
1146:   PetscReal      *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent;
1147:   IS              aIS;

1149:   PetscFunctionBegin;
1150:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1151:   PetscCall(DMGetDS(dm, &ds));
1152:   PetscCall(PetscDSGetNumFields(ds, &numFields));
1153:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1154:   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
1155:   PetscCall(ISGetIndices(aIS, &anchors));
1156:   PetscCall(PetscSectionGetChart(cSec, &conStart, &conEnd));
1157:   PetscCall(DMGetDimension(dm, &spdim));
1158:   PetscCall(PetscMalloc6(spdim, &v0, spdim, &v0parent, spdim, &vtmp, spdim * spdim, &J, spdim * spdim, &Jparent, spdim * spdim, &invJparent));

1160:   for (f = 0; f < numFields; f++) {
1161:     PetscObject          disc;
1162:     PetscClassId         id;
1163:     PetscSpace           bspace;
1164:     PetscDualSpace       dspace;
1165:     PetscInt             i, j, k, nPoints, Nc, offset;
1166:     PetscInt             fSize, maxDof;
1167:     PetscReal           *weights, *pointsRef, *pointsReal, *work;
1168:     PetscScalar         *scwork;
1169:     const PetscScalar   *X;
1170:     PetscInt            *sizes, *workIndRow, *workIndCol;
1171:     Mat                  Amat, Bmat, Xmat;
1172:     const PetscInt      *numDof = NULL;
1173:     const PetscInt    ***perms  = NULL;
1174:     const PetscScalar ***flips  = NULL;

1176:     PetscCall(PetscDSGetDiscretization(ds, f, &disc));
1177:     PetscCall(PetscObjectGetClassId(disc, &id));
1178:     if (id == PETSCFE_CLASSID) {
1179:       PetscFE fe = (PetscFE)disc;

1181:       PetscCall(PetscFEGetBasisSpace(fe, &bspace));
1182:       PetscCall(PetscFEGetDualSpace(fe, &dspace));
1183:       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
1184:       PetscCall(PetscFEGetNumComponents(fe, &Nc));
1185:     } else if (id == PETSCFV_CLASSID) {
1186:       PetscFV fv = (PetscFV)disc;

1188:       PetscCall(PetscFVGetNumComponents(fv, &Nc));
1189:       PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv), &bspace));
1190:       PetscCall(PetscSpaceSetType(bspace, PETSCSPACEPOLYNOMIAL));
1191:       PetscCall(PetscSpaceSetDegree(bspace, 0, PETSC_DETERMINE));
1192:       PetscCall(PetscSpaceSetNumComponents(bspace, Nc));
1193:       PetscCall(PetscSpaceSetNumVariables(bspace, spdim));
1194:       PetscCall(PetscSpaceSetUp(bspace));
1195:       PetscCall(PetscFVGetDualSpace(fv, &dspace));
1196:       PetscCall(PetscDualSpaceGetDimension(dspace, &fSize));
1197:     } else SETERRQ(PetscObjectComm(disc), PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id);
1198:     PetscCall(PetscDualSpaceGetNumDof(dspace, &numDof));
1199:     for (i = 0, maxDof = 0; i <= spdim; i++) maxDof = PetscMax(maxDof, numDof[i]);
1200:     PetscCall(PetscDualSpaceGetSymmetries(dspace, &perms, &flips));

1202:     PetscCall(MatCreate(PETSC_COMM_SELF, &Amat));
1203:     PetscCall(MatSetSizes(Amat, fSize, fSize, fSize, fSize));
1204:     PetscCall(MatSetType(Amat, MATSEQDENSE));
1205:     PetscCall(MatSetUp(Amat));
1206:     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Bmat));
1207:     PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Xmat));
1208:     nPoints = 0;
1209:     for (i = 0; i < fSize; i++) {
1210:       PetscInt        qPoints, thisNc;
1211:       PetscQuadrature quad;

1213:       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
1214:       PetscCall(PetscQuadratureGetData(quad, NULL, &thisNc, &qPoints, NULL, NULL));
1215:       PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
1216:       nPoints += qPoints;
1217:     }
1218:     PetscCall(PetscMalloc7(fSize, &sizes, nPoints * Nc, &weights, spdim * nPoints, &pointsRef, spdim * nPoints, &pointsReal, nPoints * fSize * Nc, &work, maxDof, &workIndRow, maxDof, &workIndCol));
1219:     PetscCall(PetscMalloc1(maxDof * maxDof, &scwork));
1220:     offset = 0;
1221:     for (i = 0; i < fSize; i++) {
1222:       PetscInt         qPoints;
1223:       const PetscReal *p, *w;
1224:       PetscQuadrature  quad;

1226:       PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad));
1227:       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &qPoints, &p, &w));
1228:       PetscCall(PetscArraycpy(weights + Nc * offset, w, Nc * qPoints));
1229:       PetscCall(PetscArraycpy(pointsRef + spdim * offset, p, spdim * qPoints));
1230:       sizes[i] = qPoints;
1231:       offset += qPoints;
1232:     }
1233:     PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsRef, weights, work, Amat));
1234:     PetscCall(MatLUFactor(Amat, NULL, NULL, NULL));
1235:     for (c = cStart; c < cEnd; c++) {
1236:       PetscInt  parent;
1237:       PetscInt  closureSize, closureSizeP, *closure = NULL, *closureP = NULL;
1238:       PetscInt *childOffsets, *parentOffsets;

1240:       PetscCall(DMPlexGetTreeParent(dm, c, &parent, NULL));
1241:       if (parent == c) continue;
1242:       PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1243:       for (i = 0; i < closureSize; i++) {
1244:         PetscInt p = closure[2 * i];
1245:         PetscInt conDof;

1247:         if (p < conStart || p >= conEnd) continue;
1248:         if (numFields) {
1249:           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
1250:         } else {
1251:           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
1252:         }
1253:         if (conDof) break;
1254:       }
1255:       if (i == closureSize) {
1256:         PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1257:         continue;
1258:       }

1260:       PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ));
1261:       PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent));
1262:       for (i = 0; i < nPoints; i++) {
1263:         const PetscReal xi0[3] = {-1., -1., -1.};

1265:         CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i * spdim], vtmp);
1266:         CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i * spdim]);
1267:       }
1268:       PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsReal, weights, work, Bmat));
1269:       PetscCall(MatMatSolve(Amat, Bmat, Xmat));
1270:       PetscCall(MatDenseGetArrayRead(Xmat, &X));
1271:       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
1272:       PetscCall(PetscMalloc2(closureSize + 1, &childOffsets, closureSizeP + 1, &parentOffsets));
1273:       childOffsets[0] = 0;
1274:       for (i = 0; i < closureSize; i++) {
1275:         PetscInt p = closure[2 * i];
1276:         PetscInt dof;

1278:         if (numFields) {
1279:           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
1280:         } else {
1281:           PetscCall(PetscSectionGetDof(section, p, &dof));
1282:         }
1283:         childOffsets[i + 1] = childOffsets[i] + dof;
1284:       }
1285:       parentOffsets[0] = 0;
1286:       for (i = 0; i < closureSizeP; i++) {
1287:         PetscInt p = closureP[2 * i];
1288:         PetscInt dof;

1290:         if (numFields) {
1291:           PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
1292:         } else {
1293:           PetscCall(PetscSectionGetDof(section, p, &dof));
1294:         }
1295:         parentOffsets[i + 1] = parentOffsets[i] + dof;
1296:       }
1297:       for (i = 0; i < closureSize; i++) {
1298:         PetscInt           conDof, conOff, aDof, aOff, nWork;
1299:         PetscInt           p = closure[2 * i];
1300:         PetscInt           o = closure[2 * i + 1];
1301:         const PetscInt    *perm;
1302:         const PetscScalar *flip;

1304:         if (p < conStart || p >= conEnd) continue;
1305:         if (numFields) {
1306:           PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof));
1307:           PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &conOff));
1308:         } else {
1309:           PetscCall(PetscSectionGetDof(cSec, p, &conDof));
1310:           PetscCall(PetscSectionGetOffset(cSec, p, &conOff));
1311:         }
1312:         if (!conDof) continue;
1313:         perm = (perms && perms[i]) ? perms[i][o] : NULL;
1314:         flip = (flips && flips[i]) ? flips[i][o] : NULL;
1315:         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
1316:         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
1317:         nWork = childOffsets[i + 1] - childOffsets[i];
1318:         for (k = 0; k < aDof; k++) {
1319:           PetscInt a = anchors[aOff + k];
1320:           PetscInt aSecDof, aSecOff;

1322:           if (numFields) {
1323:             PetscCall(PetscSectionGetFieldDof(section, a, f, &aSecDof));
1324:             PetscCall(PetscSectionGetFieldOffset(section, a, f, &aSecOff));
1325:           } else {
1326:             PetscCall(PetscSectionGetDof(section, a, &aSecDof));
1327:             PetscCall(PetscSectionGetOffset(section, a, &aSecOff));
1328:           }
1329:           if (!aSecDof) continue;

1331:           for (j = 0; j < closureSizeP; j++) {
1332:             PetscInt q  = closureP[2 * j];
1333:             PetscInt oq = closureP[2 * j + 1];

1335:             if (q == a) {
1336:               PetscInt           r, s, nWorkP;
1337:               const PetscInt    *permP;
1338:               const PetscScalar *flipP;

1340:               permP  = (perms && perms[j]) ? perms[j][oq] : NULL;
1341:               flipP  = (flips && flips[j]) ? flips[j][oq] : NULL;
1342:               nWorkP = parentOffsets[j + 1] - parentOffsets[j];
1343:               /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the
1344:                * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is
1345:                * column-major, so transpose-transpose = do nothing */
1346:               for (r = 0; r < nWork; r++) {
1347:                 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])];
1348:               }
1349:               for (r = 0; r < nWork; r++) workIndRow[perm ? perm[r] : r] = conOff + r;
1350:               for (s = 0; s < nWorkP; s++) workIndCol[permP ? permP[s] : s] = aSecOff + s;
1351:               if (flip) {
1352:                 for (r = 0; r < nWork; r++) {
1353:                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flip[r];
1354:                 }
1355:               }
1356:               if (flipP) {
1357:                 for (r = 0; r < nWork; r++) {
1358:                   for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flipP[s];
1359:                 }
1360:               }
1361:               PetscCall(MatSetValues(cMat, nWork, workIndRow, nWorkP, workIndCol, scwork, INSERT_VALUES));
1362:               break;
1363:             }
1364:           }
1365:         }
1366:       }
1367:       PetscCall(MatDenseRestoreArrayRead(Xmat, &X));
1368:       PetscCall(PetscFree2(childOffsets, parentOffsets));
1369:       PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1370:       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP));
1371:     }
1372:     PetscCall(MatDestroy(&Amat));
1373:     PetscCall(MatDestroy(&Bmat));
1374:     PetscCall(MatDestroy(&Xmat));
1375:     PetscCall(PetscFree(scwork));
1376:     PetscCall(PetscFree7(sizes, weights, pointsRef, pointsReal, work, workIndRow, workIndCol));
1377:     if (id == PETSCFV_CLASSID) PetscCall(PetscSpaceDestroy(&bspace));
1378:   }
1379:   PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
1380:   PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
1381:   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJparent));
1382:   PetscCall(ISRestoreIndices(aIS, &anchors));

1384:   PetscFunctionReturn(PETSC_SUCCESS);
1385: }

1387: static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1388: {
1389:   Mat                 refCmat;
1390:   PetscDS             ds;
1391:   PetscInt            numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN;
1392:   PetscScalar      ***refPointFieldMats;
1393:   PetscSection        refConSec, refAnSec, refSection;
1394:   IS                  refAnIS;
1395:   const PetscInt     *refAnchors;
1396:   const PetscInt    **perms;
1397:   const PetscScalar **flips;

1399:   PetscFunctionBegin;
1400:   PetscCall(DMGetDS(refTree, &ds));
1401:   PetscCall(PetscDSGetNumFields(ds, &numFields));
1402:   maxFields = PetscMax(1, numFields);
1403:   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
1404:   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
1405:   PetscCall(ISGetIndices(refAnIS, &refAnchors));
1406:   PetscCall(DMGetLocalSection(refTree, &refSection));
1407:   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
1408:   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
1409:   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldN));
1410:   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
1411:   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
1412:   PetscCall(PetscMalloc1(maxDof, &rows));
1413:   PetscCall(PetscMalloc1(maxDof * maxAnDof, &cols));
1414:   for (p = pRefStart; p < pRefEnd; p++) {
1415:     PetscInt parent, closureSize, *closure = NULL, pDof;

1417:     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
1418:     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
1419:     if (!pDof || parent == p) continue;

1421:     PetscCall(PetscMalloc1(maxFields, &refPointFieldMats[p - pRefStart]));
1422:     PetscCall(PetscCalloc1(maxFields, &refPointFieldN[p - pRefStart]));
1423:     PetscCall(DMPlexGetTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1424:     for (f = 0; f < maxFields; f++) {
1425:       PetscInt cDof, cOff, numCols, r, i;

1427:       if (f < numFields) {
1428:         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
1429:         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
1430:         PetscCall(PetscSectionGetFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1431:       } else {
1432:         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
1433:         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
1434:         PetscCall(PetscSectionGetPointSyms(refSection, closureSize, closure, &perms, &flips));
1435:       }

1437:       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
1438:       numCols = 0;
1439:       for (i = 0; i < closureSize; i++) {
1440:         PetscInt        q = closure[2 * i];
1441:         PetscInt        aDof, aOff, j;
1442:         const PetscInt *perm = perms ? perms[i] : NULL;

1444:         if (numFields) {
1445:           PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
1446:           PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
1447:         } else {
1448:           PetscCall(PetscSectionGetDof(refSection, q, &aDof));
1449:           PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1450:         }

1452:         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + (perm ? perm[j] : j);
1453:       }
1454:       refPointFieldN[p - pRefStart][f] = numCols;
1455:       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
1456:       PetscCall(MatGetValues(refCmat, cDof, rows, numCols, cols, refPointFieldMats[p - pRefStart][f]));
1457:       if (flips) {
1458:         PetscInt colOff = 0;

1460:         for (i = 0; i < closureSize; i++) {
1461:           PetscInt           q = closure[2 * i];
1462:           PetscInt           aDof, aOff, j;
1463:           const PetscScalar *flip = flips ? flips[i] : NULL;

1465:           if (numFields) {
1466:             PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof));
1467:             PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff));
1468:           } else {
1469:             PetscCall(PetscSectionGetDof(refSection, q, &aDof));
1470:             PetscCall(PetscSectionGetOffset(refSection, q, &aOff));
1471:           }
1472:           if (flip) {
1473:             PetscInt k;
1474:             for (k = 0; k < cDof; k++) {
1475:               for (j = 0; j < aDof; j++) refPointFieldMats[p - pRefStart][f][k * numCols + colOff + j] *= flip[j];
1476:             }
1477:           }
1478:           colOff += aDof;
1479:         }
1480:       }
1481:       if (numFields) {
1482:         PetscCall(PetscSectionRestoreFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips));
1483:       } else {
1484:         PetscCall(PetscSectionRestorePointSyms(refSection, closureSize, closure, &perms, &flips));
1485:       }
1486:     }
1487:     PetscCall(DMPlexRestoreTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure));
1488:   }
1489:   *childrenMats = refPointFieldMats;
1490:   *childrenN    = refPointFieldN;
1491:   PetscCall(ISRestoreIndices(refAnIS, &refAnchors));
1492:   PetscCall(PetscFree(rows));
1493:   PetscCall(PetscFree(cols));
1494:   PetscFunctionReturn(PETSC_SUCCESS);
1495: }

1497: static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN)
1498: {
1499:   PetscDS        ds;
1500:   PetscInt     **refPointFieldN;
1501:   PetscScalar ***refPointFieldMats;
1502:   PetscInt       numFields, maxFields, pRefStart, pRefEnd, p, f;
1503:   PetscSection   refConSec;

1505:   PetscFunctionBegin;
1506:   refPointFieldN    = *childrenN;
1507:   *childrenN        = NULL;
1508:   refPointFieldMats = *childrenMats;
1509:   *childrenMats     = NULL;
1510:   PetscCall(DMGetDS(refTree, &ds));
1511:   PetscCall(PetscDSGetNumFields(ds, &numFields));
1512:   maxFields = PetscMax(1, numFields);
1513:   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
1514:   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
1515:   for (p = pRefStart; p < pRefEnd; p++) {
1516:     PetscInt parent, pDof;

1518:     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
1519:     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
1520:     if (!pDof || parent == p) continue;

1522:     for (f = 0; f < maxFields; f++) {
1523:       PetscInt cDof;

1525:       if (numFields) {
1526:         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
1527:       } else {
1528:         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
1529:       }

1531:       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
1532:     }
1533:     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
1534:     PetscCall(PetscFree(refPointFieldN[p - pRefStart]));
1535:   }
1536:   PetscCall(PetscFree(refPointFieldMats));
1537:   PetscCall(PetscFree(refPointFieldN));
1538:   PetscFunctionReturn(PETSC_SUCCESS);
1539: }

1541: static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat)
1542: {
1543:   DM              refTree;
1544:   PetscDS         ds;
1545:   Mat             refCmat;
1546:   PetscInt        numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN;
1547:   PetscScalar  ***refPointFieldMats, *pointWork;
1548:   PetscSection    refConSec, refAnSec, anSec;
1549:   IS              refAnIS, anIS;
1550:   const PetscInt *anchors;

1552:   PetscFunctionBegin;
1554:   PetscCall(DMGetDS(dm, &ds));
1555:   PetscCall(PetscDSGetNumFields(ds, &numFields));
1556:   maxFields = PetscMax(1, numFields);
1557:   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
1558:   PetscCall(DMCopyDisc(dm, refTree));
1559:   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL));
1560:   PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS));
1561:   PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS));
1562:   PetscCall(ISGetIndices(anIS, &anchors));
1563:   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
1564:   PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd));
1565:   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
1566:   PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof));
1567:   PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork));

1569:   /* step 1: get submats for every constrained point in the reference tree */
1570:   PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));

1572:   /* step 2: compute the preorder */
1573:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1574:   PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm));
1575:   for (p = pStart; p < pEnd; p++) {
1576:     perm[p - pStart]  = p;
1577:     iperm[p - pStart] = p - pStart;
1578:   }
1579:   for (p = 0; p < pEnd - pStart;) {
1580:     PetscInt point = perm[p];
1581:     PetscInt parent;

1583:     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
1584:     if (parent == point) {
1585:       p++;
1586:     } else {
1587:       PetscInt size, closureSize, *closure = NULL, i;

1589:       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1590:       for (i = 0; i < closureSize; i++) {
1591:         PetscInt q = closure[2 * i];
1592:         if (iperm[q - pStart] > iperm[point - pStart]) {
1593:           /* swap */
1594:           perm[p]                 = q;
1595:           perm[iperm[q - pStart]] = point;
1596:           iperm[point - pStart]   = iperm[q - pStart];
1597:           iperm[q - pStart]       = p;
1598:           break;
1599:         }
1600:       }
1601:       size = closureSize;
1602:       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1603:       if (i == size) p++;
1604:     }
1605:   }

1607:   /* step 3: fill the constraint matrix */
1608:   /* we are going to use a preorder progressive fill strategy.  Mat doesn't
1609:    * allow progressive fill without assembly, so we are going to set up the
1610:    * values outside of the Mat first.
1611:    */
1612:   {
1613:     PetscInt        nRows, row, nnz;
1614:     PetscBool       done;
1615:     PetscInt        secStart, secEnd;
1616:     const PetscInt *ia, *ja;
1617:     PetscScalar    *vals;

1619:     PetscCall(PetscSectionGetChart(section, &secStart, &secEnd));
1620:     PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
1621:     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix");
1622:     nnz = ia[nRows];
1623:     /* malloc and then zero rows right before we fill them: this way valgrind
1624:      * can tell if we are doing progressive fill in the wrong order */
1625:     PetscCall(PetscMalloc1(nnz, &vals));
1626:     for (p = 0; p < pEnd - pStart; p++) {
1627:       PetscInt parent, childid, closureSize, *closure = NULL;
1628:       PetscInt point = perm[p], pointDof;

1630:       PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid));
1631:       if ((point < conStart) || (point >= conEnd) || (parent == point)) continue;
1632:       PetscCall(PetscSectionGetDof(conSec, point, &pointDof));
1633:       if (!pointDof) continue;
1634:       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1635:       for (f = 0; f < maxFields; f++) {
1636:         PetscInt            cDof, cOff, numCols, numFillCols, i, r, matOffset, offset;
1637:         PetscScalar        *pointMat;
1638:         const PetscInt    **perms;
1639:         const PetscScalar **flips;

1641:         if (numFields) {
1642:           PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof));
1643:           PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff));
1644:         } else {
1645:           PetscCall(PetscSectionGetDof(conSec, point, &cDof));
1646:           PetscCall(PetscSectionGetOffset(conSec, point, &cOff));
1647:         }
1648:         if (!cDof) continue;
1649:         if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1650:         else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips));

1652:         /* make sure that every row for this point is the same size */
1653:         if (PetscDefined(USE_DEBUG)) {
1654:           for (r = 0; r < cDof; r++) {
1655:             if (cDof > 1 && r) {
1656:               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]));
1657:             }
1658:           }
1659:         }
1660:         /* zero rows */
1661:         for (i = ia[cOff]; i < ia[cOff + cDof]; i++) vals[i] = 0.;
1662:         matOffset   = ia[cOff];
1663:         numFillCols = ia[cOff + 1] - matOffset;
1664:         pointMat    = refPointFieldMats[childid - pRefStart][f];
1665:         numCols     = refPointFieldN[childid - pRefStart][f];
1666:         offset      = 0;
1667:         for (i = 0; i < closureSize; i++) {
1668:           PetscInt           q = closure[2 * i];
1669:           PetscInt           aDof, aOff, j, k, qConDof, qConOff;
1670:           const PetscInt    *perm = perms ? perms[i] : NULL;
1671:           const PetscScalar *flip = flips ? flips[i] : NULL;

1673:           qConDof = qConOff = 0;
1674:           if (q < secStart || q >= secEnd) continue;
1675:           if (numFields) {
1676:             PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof));
1677:             PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff));
1678:             if (q >= conStart && q < conEnd) {
1679:               PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof));
1680:               PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff));
1681:             }
1682:           } else {
1683:             PetscCall(PetscSectionGetDof(section, q, &aDof));
1684:             PetscCall(PetscSectionGetOffset(section, q, &aOff));
1685:             if (q >= conStart && q < conEnd) {
1686:               PetscCall(PetscSectionGetDof(conSec, q, &qConDof));
1687:               PetscCall(PetscSectionGetOffset(conSec, q, &qConOff));
1688:             }
1689:           }
1690:           if (!aDof) continue;
1691:           if (qConDof) {
1692:             /* this point has anchors: its rows of the matrix should already
1693:              * be filled, thanks to preordering */
1694:             /* first multiply into pointWork, then set in matrix */
1695:             PetscInt aMatOffset   = ia[qConOff];
1696:             PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset;
1697:             for (r = 0; r < cDof; r++) {
1698:               for (j = 0; j < aNumFillCols; j++) {
1699:                 PetscScalar inVal = 0;
1700:                 for (k = 0; k < aDof; k++) {
1701:                   PetscInt col = perm ? perm[k] : k;

1703:                   inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.);
1704:                 }
1705:                 pointWork[r * aNumFillCols + j] = inVal;
1706:               }
1707:             }
1708:             /* assume that the columns are sorted, spend less time searching */
1709:             for (j = 0, k = 0; j < aNumFillCols; j++) {
1710:               PetscInt col = ja[aMatOffset + j];
1711:               for (; k < numFillCols; k++) {
1712:                 if (ja[matOffset + k] == col) break;
1713:               }
1714:               PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col);
1715:               for (r = 0; r < cDof; r++) vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j];
1716:             }
1717:           } else {
1718:             /* find where to put this portion of pointMat into the matrix */
1719:             for (k = 0; k < numFillCols; k++) {
1720:               if (ja[matOffset + k] == aOff) break;
1721:             }
1722:             PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff);
1723:             for (r = 0; r < cDof; r++) {
1724:               for (j = 0; j < aDof; j++) {
1725:                 PetscInt col = perm ? perm[j] : j;

1727:                 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.);
1728:               }
1729:             }
1730:           }
1731:           offset += aDof;
1732:         }
1733:         if (numFields) {
1734:           PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips));
1735:         } else {
1736:           PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips));
1737:         }
1738:       }
1739:       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
1740:     }
1741:     for (row = 0; row < nRows; row++) PetscCall(MatSetValues(cMat, 1, &row, ia[row + 1] - ia[row], &ja[ia[row]], &vals[ia[row]], INSERT_VALUES));
1742:     PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done));
1743:     PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix");
1744:     PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY));
1745:     PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY));
1746:     PetscCall(PetscFree(vals));
1747:   }

1749:   /* clean up */
1750:   PetscCall(ISRestoreIndices(anIS, &anchors));
1751:   PetscCall(PetscFree2(perm, iperm));
1752:   PetscCall(PetscFree(pointWork));
1753:   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
1754:   PetscFunctionReturn(PETSC_SUCCESS);
1755: }

1757: /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of
1758:  * a non-conforming mesh.  Local refinement comes later */
1759: PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm)
1760: {
1761:   DM           K;
1762:   PetscMPIInt  rank;
1763:   PetscInt     dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd;
1764:   PetscInt     numNewCones, *newConeSizes, *newCones, *newOrientations;
1765:   PetscInt    *Kembedding;
1766:   PetscInt    *cellClosure = NULL, nc;
1767:   PetscScalar *newVertexCoords;
1768:   PetscInt     numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset;
1769:   PetscSection parentSection;

1771:   PetscFunctionBegin;
1772:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1773:   PetscCall(DMGetDimension(dm, &dim));
1774:   PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm));
1775:   PetscCall(DMSetDimension(*ncdm, dim));

1777:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1778:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection));
1779:   PetscCall(DMPlexGetReferenceTree(dm, &K));
1780:   PetscCall(DMGetCoordinatesLocalSetUp(dm));
1781:   if (rank == 0) {
1782:     /* compute the new charts */
1783:     PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd));
1784:     offset = 0;
1785:     for (d = 0; d <= dim; d++) {
1786:       PetscInt pOldCount, kStart, kEnd, k;

1788:       pNewStart[d] = offset;
1789:       PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d]));
1790:       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
1791:       pOldCount = pOldEnd[d] - pOldStart[d];
1792:       /* adding the new points */
1793:       pNewCount[d] = pOldCount + kEnd - kStart;
1794:       if (!d) {
1795:         /* removing the cell */
1796:         pNewCount[d]--;
1797:       }
1798:       for (k = kStart; k < kEnd; k++) {
1799:         PetscInt parent;
1800:         PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL));
1801:         if (parent == k) {
1802:           /* avoid double counting points that won't actually be new */
1803:           pNewCount[d]--;
1804:         }
1805:       }
1806:       pNewEnd[d] = pNewStart[d] + pNewCount[d];
1807:       offset     = pNewEnd[d];
1808:     }
1809:     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]);
1810:     /* get the current closure of the cell that we are removing */
1811:     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));

1813:     PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes));
1814:     {
1815:       DMPolytopeType pct, qct;
1816:       PetscInt       kStart, kEnd, k, closureSizeK, *closureK = NULL, j;

1818:       PetscCall(DMPlexGetChart(K, &kStart, &kEnd));
1819:       PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient));

1821:       for (k = kStart; k < kEnd; k++) {
1822:         perm[k - kStart]      = k;
1823:         iperm[k - kStart]     = k - kStart;
1824:         preOrient[k - kStart] = 0;
1825:       }

1827:       PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
1828:       for (j = 1; j < closureSizeK; j++) {
1829:         PetscInt parentOrientA = closureK[2 * j + 1];
1830:         PetscInt parentOrientB = cellClosure[2 * j + 1];
1831:         PetscInt p, q;

1833:         p = closureK[2 * j];
1834:         q = cellClosure[2 * j];
1835:         PetscCall(DMPlexGetCellType(K, p, &pct));
1836:         PetscCall(DMPlexGetCellType(dm, q, &qct));
1837:         for (d = 0; d <= dim; d++) {
1838:           if (q >= pOldStart[d] && q < pOldEnd[d]) Kembedding[p] = (q - pOldStart[d]) + pNewStart[d];
1839:         }
1840:         parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA);
1841:         parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB);
1842:         if (parentOrientA != parentOrientB) {
1843:           PetscInt        numChildren, i;
1844:           const PetscInt *children;

1846:           PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children));
1847:           for (i = 0; i < numChildren; i++) {
1848:             PetscInt kPerm, oPerm;

1850:             k = children[i];
1851:             PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm));
1852:             /* perm = what refTree position I'm in */
1853:             perm[kPerm - kStart] = k;
1854:             /* iperm = who is at this position */
1855:             iperm[k - kStart]         = kPerm - kStart;
1856:             preOrient[kPerm - kStart] = oPerm;
1857:           }
1858:         }
1859:       }
1860:       PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK));
1861:     }
1862:     PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim]));
1863:     offset      = 0;
1864:     numNewCones = 0;
1865:     for (d = 0; d <= dim; d++) {
1866:       PetscInt kStart, kEnd, k;
1867:       PetscInt p;
1868:       PetscInt size;

1870:       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
1871:         /* skip cell 0 */
1872:         if (p == cell) continue;
1873:         /* old cones to new cones */
1874:         PetscCall(DMPlexGetConeSize(dm, p, &size));
1875:         newConeSizes[offset++] = size;
1876:         numNewCones += size;
1877:       }

1879:       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
1880:       for (k = kStart; k < kEnd; k++) {
1881:         PetscInt kParent;

1883:         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
1884:         if (kParent != k) {
1885:           Kembedding[k] = offset;
1886:           PetscCall(DMPlexGetConeSize(K, k, &size));
1887:           newConeSizes[offset++] = size;
1888:           numNewCones += size;
1889:           if (kParent != 0) PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1));
1890:         }
1891:       }
1892:     }

1894:     PetscCall(PetscSectionSetUp(parentSection));
1895:     PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents));
1896:     PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations));
1897:     PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs));

1899:     /* fill new cones */
1900:     offset = 0;
1901:     for (d = 0; d <= dim; d++) {
1902:       PetscInt        kStart, kEnd, k, l;
1903:       PetscInt        p;
1904:       PetscInt        size;
1905:       const PetscInt *cone, *orientation;

1907:       for (p = pOldStart[d]; p < pOldEnd[d]; p++) {
1908:         /* skip cell 0 */
1909:         if (p == cell) continue;
1910:         /* old cones to new cones */
1911:         PetscCall(DMPlexGetConeSize(dm, p, &size));
1912:         PetscCall(DMPlexGetCone(dm, p, &cone));
1913:         PetscCall(DMPlexGetConeOrientation(dm, p, &orientation));
1914:         for (l = 0; l < size; l++) {
1915:           newCones[offset]          = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1];
1916:           newOrientations[offset++] = orientation[l];
1917:         }
1918:       }

1920:       PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd));
1921:       for (k = kStart; k < kEnd; k++) {
1922:         PetscInt kPerm = perm[k], kParent;
1923:         PetscInt preO  = preOrient[k];

1925:         PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL));
1926:         if (kParent != k) {
1927:           /* embed new cones */
1928:           PetscCall(DMPlexGetConeSize(K, k, &size));
1929:           PetscCall(DMPlexGetCone(K, kPerm, &cone));
1930:           PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation));
1931:           for (l = 0; l < size; l++) {
1932:             PetscInt       q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size);
1933:             PetscInt       newO, lSize, oTrue;
1934:             DMPolytopeType ct = DM_NUM_POLYTOPES;

1936:             q                = iperm[cone[m]];
1937:             newCones[offset] = Kembedding[q];
1938:             PetscCall(DMPlexGetConeSize(K, q, &lSize));
1939:             if (lSize == 2) ct = DM_POLYTOPE_SEGMENT;
1940:             else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL;
1941:             oTrue                     = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]);
1942:             oTrue                     = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2);
1943:             newO                      = DihedralCompose(lSize, oTrue, preOrient[q]);
1944:             newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO);
1945:           }
1946:           if (kParent != 0) {
1947:             PetscInt newPoint = Kembedding[kParent];
1948:             PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset));
1949:             parents[pOffset]  = newPoint;
1950:             childIDs[pOffset] = k;
1951:           }
1952:         }
1953:       }
1954:     }

1956:     PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords));

1958:     /* fill coordinates */
1959:     offset = 0;
1960:     {
1961:       PetscInt     kStart, kEnd, l;
1962:       PetscSection vSection;
1963:       PetscInt     v;
1964:       Vec          coords;
1965:       PetscScalar *coordvals;
1966:       PetscInt     dof, off;
1967:       PetscReal    v0[3], J[9], detJ;

1969:       if (PetscDefined(USE_DEBUG)) {
1970:         PetscInt k;
1971:         PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd));
1972:         for (k = kStart; k < kEnd; k++) {
1973:           PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ));
1974:           PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k);
1975:         }
1976:       }
1977:       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ));
1978:       PetscCall(DMGetCoordinateSection(dm, &vSection));
1979:       PetscCall(DMGetCoordinatesLocal(dm, &coords));
1980:       PetscCall(VecGetArray(coords, &coordvals));
1981:       for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) {
1982:         PetscCall(PetscSectionGetDof(vSection, v, &dof));
1983:         PetscCall(PetscSectionGetOffset(vSection, v, &off));
1984:         for (l = 0; l < dof; l++) newVertexCoords[offset++] = coordvals[off + l];
1985:       }
1986:       PetscCall(VecRestoreArray(coords, &coordvals));

1988:       PetscCall(DMGetCoordinateSection(K, &vSection));
1989:       PetscCall(DMGetCoordinatesLocal(K, &coords));
1990:       PetscCall(VecGetArray(coords, &coordvals));
1991:       PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd));
1992:       for (v = kStart; v < kEnd; v++) {
1993:         PetscReal       coord[3], newCoord[3];
1994:         PetscInt        vPerm = perm[v];
1995:         PetscInt        kParent;
1996:         const PetscReal xi0[3] = {-1., -1., -1.};

1998:         PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL));
1999:         if (kParent != v) {
2000:           /* this is a new vertex */
2001:           PetscCall(PetscSectionGetOffset(vSection, vPerm, &off));
2002:           for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]);
2003:           CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord);
2004:           for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l];
2005:           offset += dim;
2006:         }
2007:       }
2008:       PetscCall(VecRestoreArray(coords, &coordvals));
2009:     }

2011:     /* need to reverse the order of pNewCount: vertices first, cells last */
2012:     for (d = 0; d < (dim + 1) / 2; d++) {
2013:       PetscInt tmp;

2015:       tmp                = pNewCount[d];
2016:       pNewCount[d]       = pNewCount[dim - d];
2017:       pNewCount[dim - d] = tmp;
2018:     }

2020:     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords));
2021:     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
2022:     PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs));

2024:     /* clean up */
2025:     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure));
2026:     PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd));
2027:     PetscCall(PetscFree(newConeSizes));
2028:     PetscCall(PetscFree2(newCones, newOrientations));
2029:     PetscCall(PetscFree(newVertexCoords));
2030:     PetscCall(PetscFree2(parents, childIDs));
2031:     PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient));
2032:   } else {
2033:     PetscInt     p, counts[4];
2034:     PetscInt    *coneSizes, *cones, *orientations;
2035:     Vec          coordVec;
2036:     PetscScalar *coords;

2038:     for (d = 0; d <= dim; d++) {
2039:       PetscInt dStart, dEnd;

2041:       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
2042:       counts[d] = dEnd - dStart;
2043:     }
2044:     PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes));
2045:     for (p = pStart; p < pEnd; p++) PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart]));
2046:     PetscCall(DMPlexGetCones(dm, &cones));
2047:     PetscCall(DMPlexGetConeOrientations(dm, &orientations));
2048:     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
2049:     PetscCall(VecGetArray(coordVec, &coords));

2051:     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
2052:     PetscCall(PetscSectionSetUp(parentSection));
2053:     PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL));
2054:     PetscCall(DMPlexSetReferenceTree(*ncdm, K));
2055:     PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL));
2056:     PetscCall(VecRestoreArray(coordVec, &coords));
2057:   }
2058:   PetscCall(PetscSectionDestroy(&parentSection));

2060:   PetscFunctionReturn(PETSC_SUCCESS);
2061: }

2063: PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
2064: {
2065:   PetscSF              coarseToFineEmbedded;
2066:   PetscSection         globalCoarse, globalFine;
2067:   PetscSection         localCoarse, localFine;
2068:   PetscSection         aSec, cSec;
2069:   PetscSection         rootIndicesSec, rootMatricesSec;
2070:   PetscSection         leafIndicesSec, leafMatricesSec;
2071:   PetscInt            *rootIndices, *leafIndices;
2072:   PetscScalar         *rootMatrices, *leafMatrices;
2073:   IS                   aIS;
2074:   const PetscInt      *anchors;
2075:   Mat                  cMat;
2076:   PetscInt             numFields, maxFields;
2077:   PetscInt             pStartC, pEndC, pStartF, pEndF, p;
2078:   PetscInt             aStart, aEnd, cStart, cEnd;
2079:   PetscInt            *maxChildIds;
2080:   PetscInt            *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
2081:   const PetscInt    ***perms;
2082:   const PetscScalar ***flips;

2084:   PetscFunctionBegin;
2085:   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
2086:   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
2087:   PetscCall(DMGetGlobalSection(fine, &globalFine));
2088:   { /* winnow fine points that don't have global dofs out of the sf */
2089:     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l;
2090:     const PetscInt *leaves;

2092:     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
2093:     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
2094:       p = leaves ? leaves[l] : l;
2095:       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
2096:       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2097:       if ((dof - cdof) > 0) numPointsWithDofs++;
2098:     }
2099:     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
2100:     for (l = 0, offset = 0; l < nleaves; l++) {
2101:       p = leaves ? leaves[l] : l;
2102:       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
2103:       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
2104:       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
2105:     }
2106:     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
2107:     PetscCall(PetscFree(pointsWithDofs));
2108:   }
2109:   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
2110:   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
2111:   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
2112:   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));
2113:   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX));

2115:   PetscCall(DMGetLocalSection(coarse, &localCoarse));
2116:   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));

2118:   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
2119:   PetscCall(ISGetIndices(aIS, &anchors));
2120:   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));

2122:   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
2123:   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));

2125:   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
2126:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
2127:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec));
2128:   PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC));
2129:   PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC));
2130:   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
2131:   maxFields = PetscMax(1, numFields);
2132:   PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO));
2133:   PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips));
2134:   PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **)));
2135:   PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **)));

2137:   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
2138:     PetscInt dof, matSize = 0;
2139:     PetscInt aDof          = 0;
2140:     PetscInt cDof          = 0;
2141:     PetscInt maxChildId    = maxChildIds[p - pStartC];
2142:     PetscInt numRowIndices = 0;
2143:     PetscInt numColIndices = 0;
2144:     PetscInt f;

2146:     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2147:     if (dof < 0) dof = -(dof + 1);
2148:     if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
2149:     if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(cSec, p, &cDof));
2150:     for (f = 0; f <= numFields; f++) offsets[f] = 0;
2151:     for (f = 0; f <= numFields; f++) newOffsets[f] = 0;
2152:     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
2153:       PetscInt *closure = NULL, closureSize, cl;

2155:       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
2156:       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
2157:         PetscInt c = closure[2 * cl], clDof;

2159:         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
2160:         numRowIndices += clDof;
2161:         for (f = 0; f < numFields; f++) {
2162:           PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof));
2163:           offsets[f + 1] += clDof;
2164:         }
2165:       }
2166:       for (f = 0; f < numFields; f++) {
2167:         offsets[f + 1] += offsets[f];
2168:         newOffsets[f + 1] = offsets[f + 1];
2169:       }
2170:       /* get the number of indices needed and their field offsets */
2171:       PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE));
2172:       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
2173:       if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */
2174:         numColIndices = numRowIndices;
2175:         matSize       = 0;
2176:       } else if (numFields) { /* we send one submat for each field: sum their sizes */
2177:         matSize = 0;
2178:         for (f = 0; f < numFields; f++) {
2179:           PetscInt numRow, numCol;

2181:           numRow = offsets[f + 1] - offsets[f];
2182:           numCol = newOffsets[f + 1] - newOffsets[f];
2183:           matSize += numRow * numCol;
2184:         }
2185:       } else {
2186:         matSize = numRowIndices * numColIndices;
2187:       }
2188:     } else if (maxChildId == -1) {
2189:       if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */
2190:         PetscInt aOff, a;

2192:         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
2193:         for (f = 0; f < numFields; f++) {
2194:           PetscInt fDof;

2196:           PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
2197:           offsets[f + 1] = fDof;
2198:         }
2199:         for (a = 0; a < aDof; a++) {
2200:           PetscInt anchor = anchors[a + aOff], aLocalDof;

2202:           PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof));
2203:           numColIndices += aLocalDof;
2204:           for (f = 0; f < numFields; f++) {
2205:             PetscInt fDof;

2207:             PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
2208:             newOffsets[f + 1] += fDof;
2209:           }
2210:         }
2211:         if (numFields) {
2212:           matSize = 0;
2213:           for (f = 0; f < numFields; f++) matSize += offsets[f + 1] * newOffsets[f + 1];
2214:         } else {
2215:           matSize = numColIndices * dof;
2216:         }
2217:       } else { /* no children, and no constraints on dofs: just get the global indices */
2218:         numColIndices = dof;
2219:         matSize       = 0;
2220:       }
2221:     }
2222:     /* we will pack the column indices with the field offsets */
2223:     PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0));
2224:     PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize));
2225:   }
2226:   PetscCall(PetscSectionSetUp(rootIndicesSec));
2227:   PetscCall(PetscSectionSetUp(rootMatricesSec));
2228:   {
2229:     PetscInt numRootIndices, numRootMatrices;

2231:     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
2232:     PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices));
2233:     PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices));
2234:     for (p = pStartC; p < pEndC; p++) {
2235:       PetscInt     numRowIndices, numColIndices, matSize, dof;
2236:       PetscInt     pIndOff, pMatOff, f;
2237:       PetscInt    *pInd;
2238:       PetscInt     maxChildId = maxChildIds[p - pStartC];
2239:       PetscScalar *pMat       = NULL;

2241:       PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices));
2242:       if (!numColIndices) continue;
2243:       for (f = 0; f <= numFields; f++) {
2244:         offsets[f]        = 0;
2245:         newOffsets[f]     = 0;
2246:         offsetsCopy[f]    = 0;
2247:         newOffsetsCopy[f] = 0;
2248:       }
2249:       numColIndices -= 2 * numFields;
2250:       PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff));
2251:       pInd = &(rootIndices[pIndOff]);
2252:       PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize));
2253:       if (matSize) {
2254:         PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff));
2255:         pMat = &rootMatrices[pMatOff];
2256:       }
2257:       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
2258:       if (dof < 0) dof = -(dof + 1);
2259:       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
2260:         PetscInt i, j;
2261:         PetscInt numRowIndices = matSize / numColIndices;

2263:         if (!numRowIndices) { /* don't need to calculate the mat, just the indices */
2264:           PetscInt numIndices, *indices;
2265:           PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
2266:           PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations");
2267:           for (i = 0; i < numColIndices; i++) pInd[i] = indices[i];
2268:           for (i = 0; i < numFields; i++) {
2269:             pInd[numColIndices + i]             = offsets[i + 1];
2270:             pInd[numColIndices + numFields + i] = offsets[i + 1];
2271:           }
2272:           PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL));
2273:         } else {
2274:           PetscInt     closureSize, *closure = NULL, cl;
2275:           PetscScalar *pMatIn, *pMatModified;
2276:           PetscInt     numPoints, *points;

2278:           PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn));
2279:           for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */
2280:             for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.;
2281:           }
2282:           PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
2283:           for (f = 0; f < maxFields; f++) {
2284:             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
2285:             else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
2286:           }
2287:           if (numFields) {
2288:             for (cl = 0; cl < closureSize; cl++) {
2289:               PetscInt c = closure[2 * cl];

2291:               for (f = 0; f < numFields; f++) {
2292:                 PetscInt fDof;

2294:                 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof));
2295:                 offsets[f + 1] += fDof;
2296:               }
2297:             }
2298:             for (f = 0; f < numFields; f++) {
2299:               offsets[f + 1] += offsets[f];
2300:               newOffsets[f + 1] = offsets[f + 1];
2301:             }
2302:           }
2303:           /* TODO : flips here ? */
2304:           /* apply hanging node constraints on the right, get the new points and the new offsets */
2305:           PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE));
2306:           for (f = 0; f < maxFields; f++) {
2307:             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f]));
2308:             else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f]));
2309:           }
2310:           for (f = 0; f < maxFields; f++) {
2311:             if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
2312:             else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
2313:           }
2314:           if (!numFields) {
2315:             for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i];
2316:           } else {
2317:             PetscInt i, j, count;
2318:             for (f = 0, count = 0; f < numFields; f++) {
2319:               for (i = offsets[f]; i < offsets[f + 1]; i++) {
2320:                 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j];
2321:               }
2322:             }
2323:           }
2324:           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified));
2325:           PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
2326:           PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn));
2327:           if (numFields) {
2328:             for (f = 0; f < numFields; f++) {
2329:               pInd[numColIndices + f]             = offsets[f + 1];
2330:               pInd[numColIndices + numFields + f] = newOffsets[f + 1];
2331:             }
2332:             for (cl = 0; cl < numPoints; cl++) {
2333:               PetscInt globalOff, c = points[2 * cl];
2334:               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
2335:               PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd));
2336:             }
2337:           } else {
2338:             for (cl = 0; cl < numPoints; cl++) {
2339:               PetscInt        c    = points[2 * cl], globalOff;
2340:               const PetscInt *perm = perms[0] ? perms[0][cl] : NULL;

2342:               PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff));
2343:               PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd));
2344:             }
2345:           }
2346:           for (f = 0; f < maxFields; f++) {
2347:             if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f]));
2348:             else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f]));
2349:           }
2350:           PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points));
2351:         }
2352:       } else if (matSize) {
2353:         PetscInt  cOff;
2354:         PetscInt *rowIndices, *colIndices, a, aDof, aOff;

2356:         numRowIndices = matSize / numColIndices;
2357:         PetscCheck(numRowIndices == dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Miscounted dofs");
2358:         PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
2359:         PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
2360:         PetscCall(PetscSectionGetOffset(cSec, p, &cOff));
2361:         PetscCall(PetscSectionGetDof(aSec, p, &aDof));
2362:         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
2363:         if (numFields) {
2364:           for (f = 0; f < numFields; f++) {
2365:             PetscInt fDof;

2367:             PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof));
2368:             offsets[f + 1] = fDof;
2369:             for (a = 0; a < aDof; a++) {
2370:               PetscInt anchor = anchors[a + aOff];
2371:               PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof));
2372:               newOffsets[f + 1] += fDof;
2373:             }
2374:           }
2375:           for (f = 0; f < numFields; f++) {
2376:             offsets[f + 1] += offsets[f];
2377:             offsetsCopy[f + 1] = offsets[f + 1];
2378:             newOffsets[f + 1] += newOffsets[f];
2379:             newOffsetsCopy[f + 1] = newOffsets[f + 1];
2380:           }
2381:           PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices));
2382:           for (a = 0; a < aDof; a++) {
2383:             PetscInt anchor = anchors[a + aOff], lOff;
2384:             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
2385:             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices));
2386:           }
2387:         } else {
2388:           PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices));
2389:           for (a = 0; a < aDof; a++) {
2390:             PetscInt anchor = anchors[a + aOff], lOff;
2391:             PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff));
2392:             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices));
2393:           }
2394:         }
2395:         if (numFields) {
2396:           PetscInt count, a;

2398:           for (f = 0, count = 0; f < numFields; f++) {
2399:             PetscInt iSize = offsets[f + 1] - offsets[f];
2400:             PetscInt jSize = newOffsets[f + 1] - newOffsets[f];
2401:             PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count]));
2402:             count += iSize * jSize;
2403:             pInd[numColIndices + f]             = offsets[f + 1];
2404:             pInd[numColIndices + numFields + f] = newOffsets[f + 1];
2405:           }
2406:           for (a = 0; a < aDof; a++) {
2407:             PetscInt anchor = anchors[a + aOff];
2408:             PetscInt gOff;
2409:             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
2410:             PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2411:           }
2412:         } else {
2413:           PetscInt a;
2414:           PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat));
2415:           for (a = 0; a < aDof; a++) {
2416:             PetscInt anchor = anchors[a + aOff];
2417:             PetscInt gOff;
2418:             PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff));
2419:             PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd));
2420:           }
2421:         }
2422:         PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices));
2423:         PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices));
2424:       } else {
2425:         PetscInt gOff;

2427:         PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));
2428:         if (numFields) {
2429:           for (f = 0; f < numFields; f++) {
2430:             PetscInt fDof;
2431:             PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
2432:             offsets[f + 1] = fDof + offsets[f];
2433:           }
2434:           for (f = 0; f < numFields; f++) {
2435:             pInd[numColIndices + f]             = offsets[f + 1];
2436:             pInd[numColIndices + numFields + f] = offsets[f + 1];
2437:           }
2438:           PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
2439:         } else {
2440:           PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
2441:         }
2442:       }
2443:     }
2444:     PetscCall(PetscFree(maxChildIds));
2445:   }
2446:   {
2447:     PetscSF   indicesSF, matricesSF;
2448:     PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices;

2450:     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
2451:     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec));
2452:     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec));
2453:     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec));
2454:     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF));
2455:     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF));
2456:     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
2457:     PetscCall(PetscFree(remoteOffsetsIndices));
2458:     PetscCall(PetscFree(remoteOffsetsMatrices));
2459:     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices));
2460:     PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices));
2461:     PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices));
2462:     PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
2463:     PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
2464:     PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE));
2465:     PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE));
2466:     PetscCall(PetscSFDestroy(&matricesSF));
2467:     PetscCall(PetscSFDestroy(&indicesSF));
2468:     PetscCall(PetscFree2(rootIndices, rootMatrices));
2469:     PetscCall(PetscSectionDestroy(&rootIndicesSec));
2470:     PetscCall(PetscSectionDestroy(&rootMatricesSec));
2471:   }
2472:   /* count to preallocate */
2473:   PetscCall(DMGetLocalSection(fine, &localFine));
2474:   {
2475:     PetscInt       nGlobal;
2476:     PetscInt      *dnnz, *onnz;
2477:     PetscLayout    rowMap, colMap;
2478:     PetscInt       rowStart, rowEnd, colStart, colEnd;
2479:     PetscInt       maxDof;
2480:     PetscInt      *rowIndices;
2481:     DM             refTree;
2482:     PetscInt     **refPointFieldN;
2483:     PetscScalar ***refPointFieldMats;
2484:     PetscSection   refConSec, refAnSec;
2485:     PetscInt       pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd;
2486:     PetscScalar   *pointWork;

2488:     PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal));
2489:     PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz));
2490:     PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
2491:     PetscCall(PetscLayoutSetUp(rowMap));
2492:     PetscCall(PetscLayoutSetUp(colMap));
2493:     PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
2494:     PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
2495:     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
2496:     PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd));
2497:     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
2498:     for (p = leafStart; p < leafEnd; p++) {
2499:       PetscInt gDof, gcDof, gOff;
2500:       PetscInt numColIndices, pIndOff, *pInd;
2501:       PetscInt matSize;
2502:       PetscInt i;

2504:       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
2505:       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2506:       if ((gDof - gcDof) <= 0) continue;
2507:       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
2508:       PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset");
2509:       PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs");
2510:       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
2511:       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2512:       numColIndices -= 2 * numFields;
2513:       PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from");
2514:       pInd              = &leafIndices[pIndOff];
2515:       offsets[0]        = 0;
2516:       offsetsCopy[0]    = 0;
2517:       newOffsets[0]     = 0;
2518:       newOffsetsCopy[0] = 0;
2519:       if (numFields) {
2520:         PetscInt f;
2521:         for (f = 0; f < numFields; f++) {
2522:           PetscInt rowDof;

2524:           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2525:           offsets[f + 1]     = offsets[f] + rowDof;
2526:           offsetsCopy[f + 1] = offsets[f + 1];
2527:           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2528:           numD[f]            = 0;
2529:           numO[f]            = 0;
2530:         }
2531:         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
2532:         for (f = 0; f < numFields; f++) {
2533:           PetscInt colOffset    = newOffsets[f];
2534:           PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f];

2536:           for (i = 0; i < numFieldCols; i++) {
2537:             PetscInt gInd = pInd[i + colOffset];

2539:             if (gInd >= colStart && gInd < colEnd) {
2540:               numD[f]++;
2541:             } else if (gInd >= 0) { /* negative means non-entry */
2542:               numO[f]++;
2543:             }
2544:           }
2545:         }
2546:       } else {
2547:         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
2548:         numD[0] = 0;
2549:         numO[0] = 0;
2550:         for (i = 0; i < numColIndices; i++) {
2551:           PetscInt gInd = pInd[i];

2553:           if (gInd >= colStart && gInd < colEnd) {
2554:             numD[0]++;
2555:           } else if (gInd >= 0) { /* negative means non-entry */
2556:             numO[0]++;
2557:           }
2558:         }
2559:       }
2560:       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2561:       if (!matSize) { /* incoming matrix is identity */
2562:         PetscInt childId;

2564:         childId = childIds[p - pStartF];
2565:         if (childId < 0) { /* no child interpolation: one nnz per */
2566:           if (numFields) {
2567:             PetscInt f;
2568:             for (f = 0; f < numFields; f++) {
2569:               PetscInt numRows = offsets[f + 1] - offsets[f], row;
2570:               for (row = 0; row < numRows; row++) {
2571:                 PetscInt gIndCoarse = pInd[newOffsets[f] + row];
2572:                 PetscInt gIndFine   = rowIndices[offsets[f] + row];
2573:                 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2574:                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2575:                   dnnz[gIndFine - rowStart] = 1;
2576:                 } else if (gIndCoarse >= 0) { /* remote */
2577:                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2578:                   onnz[gIndFine - rowStart] = 1;
2579:                 } else { /* constrained */
2580:                   PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2581:                 }
2582:               }
2583:             }
2584:           } else {
2585:             PetscInt i;
2586:             for (i = 0; i < gDof; i++) {
2587:               PetscInt gIndCoarse = pInd[i];
2588:               PetscInt gIndFine   = rowIndices[i];
2589:               if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */
2590:                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2591:                 dnnz[gIndFine - rowStart] = 1;
2592:               } else if (gIndCoarse >= 0) { /* remote */
2593:                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2594:                 onnz[gIndFine - rowStart] = 1;
2595:               } else { /* constrained */
2596:                 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2597:               }
2598:             }
2599:           }
2600:         } else { /* interpolate from all */
2601:           if (numFields) {
2602:             PetscInt f;
2603:             for (f = 0; f < numFields; f++) {
2604:               PetscInt numRows = offsets[f + 1] - offsets[f], row;
2605:               for (row = 0; row < numRows; row++) {
2606:                 PetscInt gIndFine = rowIndices[offsets[f] + row];
2607:                 if (gIndFine >= 0) {
2608:                   PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2609:                   dnnz[gIndFine - rowStart] = numD[f];
2610:                   onnz[gIndFine - rowStart] = numO[f];
2611:                 }
2612:               }
2613:             }
2614:           } else {
2615:             PetscInt i;
2616:             for (i = 0; i < gDof; i++) {
2617:               PetscInt gIndFine = rowIndices[i];
2618:               if (gIndFine >= 0) {
2619:                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2620:                 dnnz[gIndFine - rowStart] = numD[0];
2621:                 onnz[gIndFine - rowStart] = numO[0];
2622:               }
2623:             }
2624:           }
2625:         }
2626:       } else { /* interpolate from all */
2627:         if (numFields) {
2628:           PetscInt f;
2629:           for (f = 0; f < numFields; f++) {
2630:             PetscInt numRows = offsets[f + 1] - offsets[f], row;
2631:             for (row = 0; row < numRows; row++) {
2632:               PetscInt gIndFine = rowIndices[offsets[f] + row];
2633:               if (gIndFine >= 0) {
2634:                 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2635:                 dnnz[gIndFine - rowStart] = numD[f];
2636:                 onnz[gIndFine - rowStart] = numO[f];
2637:               }
2638:             }
2639:           }
2640:         } else { /* every dof get a full row */
2641:           PetscInt i;
2642:           for (i = 0; i < gDof; i++) {
2643:             PetscInt gIndFine = rowIndices[i];
2644:             if (gIndFine >= 0) {
2645:               PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs");
2646:               dnnz[gIndFine - rowStart] = numD[0];
2647:               onnz[gIndFine - rowStart] = numO[0];
2648:             }
2649:           }
2650:         }
2651:       }
2652:     }
2653:     PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL));
2654:     PetscCall(PetscFree2(dnnz, onnz));

2656:     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
2657:     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
2658:     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
2659:     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
2660:     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
2661:     PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof));
2662:     PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns));
2663:     PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork));
2664:     for (p = leafStart; p < leafEnd; p++) {
2665:       PetscInt gDof, gcDof, gOff;
2666:       PetscInt numColIndices, pIndOff, *pInd;
2667:       PetscInt matSize;
2668:       PetscInt childId;

2670:       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
2671:       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
2672:       if ((gDof - gcDof) <= 0) continue;
2673:       childId = childIds[p - pStartF];
2674:       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
2675:       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices));
2676:       PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff));
2677:       numColIndices -= 2 * numFields;
2678:       pInd              = &leafIndices[pIndOff];
2679:       offsets[0]        = 0;
2680:       offsetsCopy[0]    = 0;
2681:       newOffsets[0]     = 0;
2682:       newOffsetsCopy[0] = 0;
2683:       rowOffsets[0]     = 0;
2684:       if (numFields) {
2685:         PetscInt f;
2686:         for (f = 0; f < numFields; f++) {
2687:           PetscInt rowDof;

2689:           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
2690:           offsets[f + 1]     = offsets[f] + rowDof;
2691:           offsetsCopy[f + 1] = offsets[f + 1];
2692:           rowOffsets[f + 1]  = pInd[numColIndices + f];
2693:           newOffsets[f + 1]  = pInd[numColIndices + numFields + f];
2694:         }
2695:         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
2696:       } else {
2697:         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
2698:       }
2699:       PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize));
2700:       if (!matSize) {      /* incoming matrix is identity */
2701:         if (childId < 0) { /* no child interpolation: scatter */
2702:           if (numFields) {
2703:             PetscInt f;
2704:             for (f = 0; f < numFields; f++) {
2705:               PetscInt numRows = offsets[f + 1] - offsets[f], row;
2706:               for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES));
2707:             }
2708:           } else {
2709:             PetscInt numRows = gDof, row;
2710:             for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES));
2711:           }
2712:         } else { /* interpolate from all */
2713:           if (numFields) {
2714:             PetscInt f;
2715:             for (f = 0; f < numFields; f++) {
2716:               PetscInt numRows = offsets[f + 1] - offsets[f];
2717:               PetscInt numCols = newOffsets[f + 1] - newOffsets[f];
2718:               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES));
2719:             }
2720:           } else {
2721:             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES));
2722:           }
2723:         }
2724:       } else { /* interpolate from all */
2725:         PetscInt     pMatOff;
2726:         PetscScalar *pMat;

2728:         PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff));
2729:         pMat = &leafMatrices[pMatOff];
2730:         if (childId < 0) { /* copy the incoming matrix */
2731:           if (numFields) {
2732:             PetscInt f, count;
2733:             for (f = 0, count = 0; f < numFields; f++) {
2734:               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2735:               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2736:               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2737:               PetscScalar *inMat     = &pMat[count];

2739:               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES));
2740:               count += numCols * numInRows;
2741:             }
2742:           } else {
2743:             PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES));
2744:           }
2745:         } else { /* multiply the incoming matrix by the child interpolation */
2746:           if (numFields) {
2747:             PetscInt f, count;
2748:             for (f = 0, count = 0; f < numFields; f++) {
2749:               PetscInt     numRows   = offsets[f + 1] - offsets[f];
2750:               PetscInt     numCols   = newOffsets[f + 1] - newOffsets[f];
2751:               PetscInt     numInRows = rowOffsets[f + 1] - rowOffsets[f];
2752:               PetscScalar *inMat     = &pMat[count];
2753:               PetscInt     i, j, k;
2754:               PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2755:               for (i = 0; i < numRows; i++) {
2756:                 for (j = 0; j < numCols; j++) {
2757:                   PetscScalar val = 0.;
2758:                   for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j];
2759:                   pointWork[i * numCols + j] = val;
2760:                 }
2761:               }
2762:               PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES));
2763:               count += numCols * numInRows;
2764:             }
2765:           } else { /* every dof gets a full row */
2766:             PetscInt numRows   = gDof;
2767:             PetscInt numCols   = numColIndices;
2768:             PetscInt numInRows = matSize / numColIndices;
2769:             PetscInt i, j, k;
2770:             PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch");
2771:             for (i = 0; i < numRows; i++) {
2772:               for (j = 0; j < numCols; j++) {
2773:                 PetscScalar val = 0.;
2774:                 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j];
2775:                 pointWork[i * numCols + j] = val;
2776:               }
2777:             }
2778:             PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES));
2779:           }
2780:         }
2781:       }
2782:     }
2783:     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
2784:     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
2785:     PetscCall(PetscFree(pointWork));
2786:   }
2787:   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
2788:   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
2789:   PetscCall(PetscSectionDestroy(&leafIndicesSec));
2790:   PetscCall(PetscSectionDestroy(&leafMatricesSec));
2791:   PetscCall(PetscFree2(leafIndices, leafMatrices));
2792:   PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips));
2793:   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
2794:   PetscCall(ISRestoreIndices(aIS, &anchors));
2795:   PetscFunctionReturn(PETSC_SUCCESS);
2796: }

2798: /*
2799:  * Assuming a nodal basis (w.r.t. the dual basis) basis:
2800:  *
2801:  * for each coarse dof \phi^c_i:
2802:  *   for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i:
2803:  *     for each fine dof \phi^f_j;
2804:  *       a_{i,j} = 0;
2805:  *       for each fine dof \phi^f_k:
2806:  *         a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l
2807:  *                    [^^^ this is = \phi^c_i ^^^]
2808:  */
2809: PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj)
2810: {
2811:   PetscDS      ds;
2812:   PetscSection section, cSection;
2813:   DMLabel      canonical, depth;
2814:   Mat          cMat, mat;
2815:   PetscInt    *nnz;
2816:   PetscInt     f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd;
2817:   PetscInt     m, n;
2818:   PetscScalar *pointScalar;
2819:   PetscReal   *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent;

2821:   PetscFunctionBegin;
2822:   PetscCall(DMGetLocalSection(refTree, &section));
2823:   PetscCall(DMGetDimension(refTree, &dim));
2824:   PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ));
2825:   PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef));
2826:   PetscCall(DMGetDS(refTree, &ds));
2827:   PetscCall(PetscDSGetNumFields(ds, &numFields));
2828:   PetscCall(PetscSectionGetNumFields(section, &numSecFields));
2829:   PetscCall(DMGetLabel(refTree, "canonical", &canonical));
2830:   PetscCall(DMGetLabel(refTree, "depth", &depth));
2831:   PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL));
2832:   PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd));
2833:   PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd));
2834:   PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */
2835:   /* Step 1: compute non-zero pattern.  A proper subset of constraint matrix non-zero */
2836:   PetscCall(PetscCalloc1(m, &nnz));
2837:   for (p = pStart; p < pEnd; p++) { /* a point will have non-zeros if it is canonical, it has dofs, and its children have dofs */
2838:     const PetscInt *children;
2839:     PetscInt        numChildren;
2840:     PetscInt        i, numChildDof, numSelfDof;

2842:     if (canonical) {
2843:       PetscInt pCanonical;
2844:       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
2845:       if (p != pCanonical) continue;
2846:     }
2847:     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
2848:     if (!numChildren) continue;
2849:     for (i = 0, numChildDof = 0; i < numChildren; i++) {
2850:       PetscInt child = children[i];
2851:       PetscInt dof;

2853:       PetscCall(PetscSectionGetDof(section, child, &dof));
2854:       numChildDof += dof;
2855:     }
2856:     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
2857:     if (!numChildDof || !numSelfDof) continue;
2858:     for (f = 0; f < numFields; f++) {
2859:       PetscInt selfOff;

2861:       if (numSecFields) { /* count the dofs for just this field */
2862:         for (i = 0, numChildDof = 0; i < numChildren; i++) {
2863:           PetscInt child = children[i];
2864:           PetscInt dof;

2866:           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
2867:           numChildDof += dof;
2868:         }
2869:         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
2870:         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
2871:       } else {
2872:         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
2873:       }
2874:       for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof;
2875:     }
2876:   }
2877:   PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat));
2878:   PetscCall(PetscFree(nnz));
2879:   /* Setp 2: compute entries */
2880:   for (p = pStart; p < pEnd; p++) {
2881:     const PetscInt *children;
2882:     PetscInt        numChildren;
2883:     PetscInt        i, numChildDof, numSelfDof;

2885:     /* same conditions about when entries occur */
2886:     if (canonical) {
2887:       PetscInt pCanonical;
2888:       PetscCall(DMLabelGetValue(canonical, p, &pCanonical));
2889:       if (p != pCanonical) continue;
2890:     }
2891:     PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children));
2892:     if (!numChildren) continue;
2893:     for (i = 0, numChildDof = 0; i < numChildren; i++) {
2894:       PetscInt child = children[i];
2895:       PetscInt dof;

2897:       PetscCall(PetscSectionGetDof(section, child, &dof));
2898:       numChildDof += dof;
2899:     }
2900:     PetscCall(PetscSectionGetDof(section, p, &numSelfDof));
2901:     if (!numChildDof || !numSelfDof) continue;

2903:     for (f = 0; f < numFields; f++) {
2904:       PetscInt        pI = -1, cI = -1;
2905:       PetscInt        selfOff, Nc, parentCell;
2906:       PetscInt        cellShapeOff;
2907:       PetscObject     disc;
2908:       PetscDualSpace  dsp;
2909:       PetscClassId    classId;
2910:       PetscScalar    *pointMat;
2911:       PetscInt       *matRows, *matCols;
2912:       PetscInt        pO = PETSC_MIN_INT;
2913:       const PetscInt *depthNumDof;

2915:       if (numSecFields) {
2916:         for (i = 0, numChildDof = 0; i < numChildren; i++) {
2917:           PetscInt child = children[i];
2918:           PetscInt dof;

2920:           PetscCall(PetscSectionGetFieldDof(section, child, f, &dof));
2921:           numChildDof += dof;
2922:         }
2923:         PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof));
2924:         PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff));
2925:       } else {
2926:         PetscCall(PetscSectionGetOffset(section, p, &selfOff));
2927:       }

2929:       /* find a cell whose closure contains p */
2930:       if (p >= cStart && p < cEnd) {
2931:         parentCell = p;
2932:       } else {
2933:         PetscInt *star = NULL;
2934:         PetscInt  numStar;

2936:         parentCell = -1;
2937:         PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
2938:         for (i = numStar - 1; i >= 0; i--) {
2939:           PetscInt c = star[2 * i];

2941:           if (c >= cStart && c < cEnd) {
2942:             parentCell = c;
2943:             break;
2944:           }
2945:         }
2946:         PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star));
2947:       }
2948:       /* determine the offset of p's shape functions within parentCell's shape functions */
2949:       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
2950:       PetscCall(PetscObjectGetClassId(disc, &classId));
2951:       if (classId == PETSCFE_CLASSID) {
2952:         PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
2953:       } else if (classId == PETSCFV_CLASSID) {
2954:         PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp));
2955:       } else {
2956:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object");
2957:       }
2958:       PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof));
2959:       PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc));
2960:       {
2961:         PetscInt *closure = NULL;
2962:         PetscInt  numClosure;

2964:         PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
2965:         for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) {
2966:           PetscInt point = closure[2 * i], pointDepth;

2968:           pO = closure[2 * i + 1];
2969:           if (point == p) {
2970:             pI = i;
2971:             break;
2972:           }
2973:           PetscCall(DMLabelGetValue(depth, point, &pointDepth));
2974:           cellShapeOff += depthNumDof[pointDepth];
2975:         }
2976:         PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure));
2977:       }

2979:       PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
2980:       PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
2981:       matCols = matRows + numSelfDof;
2982:       for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i;
2983:       for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.;
2984:       {
2985:         PetscInt colOff = 0;

2987:         for (i = 0; i < numChildren; i++) {
2988:           PetscInt child = children[i];
2989:           PetscInt dof, off, j;

2991:           if (numSecFields) {
2992:             PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof));
2993:             PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off));
2994:           } else {
2995:             PetscCall(PetscSectionGetDof(cSection, child, &dof));
2996:             PetscCall(PetscSectionGetOffset(cSection, child, &off));
2997:           }

2999:           for (j = 0; j < dof; j++) matCols[colOff++] = off + j;
3000:         }
3001:       }
3002:       if (classId == PETSCFE_CLASSID) {
3003:         PetscFE              fe = (PetscFE)disc;
3004:         PetscInt             fSize;
3005:         const PetscInt    ***perms;
3006:         const PetscScalar ***flips;
3007:         const PetscInt      *pperms;

3009:         PetscCall(PetscFEGetDualSpace(fe, &dsp));
3010:         PetscCall(PetscDualSpaceGetDimension(dsp, &fSize));
3011:         PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips));
3012:         pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL;
3013:         for (i = 0; i < numSelfDof; i++) { /* for every shape function */
3014:           PetscQuadrature  q;
3015:           PetscInt         dim, thisNc, numPoints, j, k;
3016:           const PetscReal *points;
3017:           const PetscReal *weights;
3018:           PetscInt        *closure = NULL;
3019:           PetscInt         numClosure;
3020:           PetscInt         iCell              = pperms ? pperms[i] : i;
3021:           PetscInt         parentCellShapeDof = cellShapeOff + iCell;
3022:           PetscTabulation  Tparent;

3024:           PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q));
3025:           PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights));
3026:           PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc);
3027:           PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */
3028:           for (j = 0; j < numPoints; j++) {
3029:             PetscInt           childCell = -1;
3030:             PetscReal         *parentValAtPoint;
3031:             const PetscReal    xi0[3]    = {-1., -1., -1.};
3032:             const PetscReal   *pointReal = &points[dim * j];
3033:             const PetscScalar *point;
3034:             PetscTabulation    Tchild;
3035:             PetscInt           childCellShapeOff, pointMatOff;
3036: #if defined(PETSC_USE_COMPLEX)
3037:             PetscInt d;

3039:             for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d];
3040:             point = pointScalar;
3041: #else
3042:             point = pointReal;
3043: #endif

3045:             parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc];

3047:             for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/
3048:               PetscInt  child = children[k];
3049:               PetscInt *star  = NULL;
3050:               PetscInt  numStar, s;

3052:               PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
3053:               for (s = numStar - 1; s >= 0; s--) {
3054:                 PetscInt c = star[2 * s];

3056:                 if (c < cStart || c >= cEnd) continue;
3057:                 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell));
3058:                 if (childCell >= 0) break;
3059:               }
3060:               PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star));
3061:               if (childCell >= 0) break;
3062:             }
3063:             PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point");
3064:             PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ));
3065:             PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent));
3066:             CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp);
3067:             CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef);

3069:             PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild));
3070:             PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
3071:             for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */
3072:               PetscInt        child = children[k], childDepth, childDof, childO = PETSC_MIN_INT;
3073:               PetscInt        l;
3074:               const PetscInt *cperms;

3076:               PetscCall(DMLabelGetValue(depth, child, &childDepth));
3077:               childDof = depthNumDof[childDepth];
3078:               for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) {
3079:                 PetscInt point = closure[2 * l];
3080:                 PetscInt pointDepth;

3082:                 childO = closure[2 * l + 1];
3083:                 if (point == child) {
3084:                   cI = l;
3085:                   break;
3086:                 }
3087:                 PetscCall(DMLabelGetValue(depth, point, &pointDepth));
3088:                 childCellShapeOff += depthNumDof[pointDepth];
3089:               }
3090:               if (l == numClosure) {
3091:                 pointMatOff += childDof;
3092:                 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */
3093:               }
3094:               cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL;
3095:               for (l = 0; l < childDof; l++) {
3096:                 PetscInt   lCell        = cperms ? cperms[l] : l;
3097:                 PetscInt   childCellDof = childCellShapeOff + lCell;
3098:                 PetscReal *childValAtPoint;
3099:                 PetscReal  val = 0.;

3101:                 childValAtPoint = &Tchild->T[0][childCellDof * Nc];
3102:                 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m];

3104:                 pointMat[i * numChildDof + pointMatOff + l] += val;
3105:               }
3106:               pointMatOff += childDof;
3107:             }
3108:             PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure));
3109:             PetscCall(PetscTabulationDestroy(&Tchild));
3110:           }
3111:           PetscCall(PetscTabulationDestroy(&Tparent));
3112:         }
3113:       } else { /* just the volume-weighted averages of the children */
3114:         PetscReal parentVol;
3115:         PetscInt  childCell;

3117:         PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL));
3118:         for (i = 0, childCell = 0; i < numChildren; i++) {
3119:           PetscInt  child = children[i], j;
3120:           PetscReal childVol;

3122:           if (child < cStart || child >= cEnd) continue;
3123:           PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL));
3124:           for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol;
3125:           childCell++;
3126:         }
3127:       }
3128:       /* Insert pointMat into mat */
3129:       PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES));
3130:       PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows));
3131:       PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat));
3132:     }
3133:   }
3134:   PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ));
3135:   PetscCall(PetscFree2(pointScalar, pointRef));
3136:   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
3137:   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
3138:   *inj = mat;
3139:   PetscFunctionReturn(PETSC_SUCCESS);
3140: }

3142: static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3143: {
3144:   PetscDS        ds;
3145:   PetscInt       numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof;
3146:   PetscScalar ***refPointFieldMats;
3147:   PetscSection   refConSec, refSection;

3149:   PetscFunctionBegin;
3150:   PetscCall(DMGetDS(refTree, &ds));
3151:   PetscCall(PetscDSGetNumFields(ds, &numFields));
3152:   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
3153:   PetscCall(DMGetLocalSection(refTree, &refSection));
3154:   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3155:   PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats));
3156:   PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof));
3157:   PetscCall(PetscMalloc1(maxDof, &rows));
3158:   PetscCall(PetscMalloc1(maxDof * maxDof, &cols));
3159:   for (p = pRefStart; p < pRefEnd; p++) {
3160:     PetscInt parent, pDof, parentDof;

3162:     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
3163:     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
3164:     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3165:     if (!pDof || !parentDof || parent == p) continue;

3167:     PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart]));
3168:     for (f = 0; f < numFields; f++) {
3169:       PetscInt cDof, cOff, numCols, r;

3171:       if (numFields > 1) {
3172:         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
3173:         PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff));
3174:       } else {
3175:         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3176:         PetscCall(PetscSectionGetOffset(refConSec, p, &cOff));
3177:       }

3179:       for (r = 0; r < cDof; r++) rows[r] = cOff + r;
3180:       numCols = 0;
3181:       {
3182:         PetscInt aDof, aOff, j;

3184:         if (numFields > 1) {
3185:           PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof));
3186:           PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff));
3187:         } else {
3188:           PetscCall(PetscSectionGetDof(refSection, parent, &aDof));
3189:           PetscCall(PetscSectionGetOffset(refSection, parent, &aOff));
3190:         }

3192:         for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j;
3193:       }
3194:       PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f]));
3195:       /* transpose of constraint matrix */
3196:       PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f]));
3197:     }
3198:   }
3199:   *childrenMats = refPointFieldMats;
3200:   PetscCall(PetscFree(rows));
3201:   PetscCall(PetscFree(cols));
3202:   PetscFunctionReturn(PETSC_SUCCESS);
3203: }

3205: static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats)
3206: {
3207:   PetscDS        ds;
3208:   PetscScalar ***refPointFieldMats;
3209:   PetscInt       numFields, pRefStart, pRefEnd, p, f;
3210:   PetscSection   refConSec, refSection;

3212:   PetscFunctionBegin;
3213:   refPointFieldMats = *childrenMats;
3214:   *childrenMats     = NULL;
3215:   PetscCall(DMGetDS(refTree, &ds));
3216:   PetscCall(DMGetLocalSection(refTree, &refSection));
3217:   PetscCall(PetscDSGetNumFields(ds, &numFields));
3218:   PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
3219:   PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3220:   for (p = pRefStart; p < pRefEnd; p++) {
3221:     PetscInt parent, pDof, parentDof;

3223:     PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL));
3224:     PetscCall(PetscSectionGetDof(refConSec, p, &pDof));
3225:     PetscCall(PetscSectionGetDof(refSection, parent, &parentDof));
3226:     if (!pDof || !parentDof || parent == p) continue;

3228:     for (f = 0; f < numFields; f++) {
3229:       PetscInt cDof;

3231:       if (numFields > 1) {
3232:         PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof));
3233:       } else {
3234:         PetscCall(PetscSectionGetDof(refConSec, p, &cDof));
3235:       }

3237:       PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f]));
3238:     }
3239:     PetscCall(PetscFree(refPointFieldMats[p - pRefStart]));
3240:   }
3241:   PetscCall(PetscFree(refPointFieldMats));
3242:   PetscFunctionReturn(PETSC_SUCCESS);
3243: }

3245: static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef)
3246: {
3247:   Mat         cMatRef;
3248:   PetscObject injRefObj;

3250:   PetscFunctionBegin;
3251:   PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL));
3252:   PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj));
3253:   *injRef = (Mat)injRefObj;
3254:   if (!*injRef) {
3255:     PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef));
3256:     PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef));
3257:     /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */
3258:     PetscCall(PetscObjectDereference((PetscObject)*injRef));
3259:   }
3260:   PetscFunctionReturn(PETSC_SUCCESS);
3261: }

3263: 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)
3264: {
3265:   PetscInt        pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti;
3266:   PetscSection    globalCoarse, globalFine;
3267:   PetscSection    localCoarse, localFine, leafIndicesSec;
3268:   PetscSection    multiRootSec, rootIndicesSec;
3269:   PetscInt       *leafInds, *rootInds = NULL;
3270:   const PetscInt *rootDegrees;
3271:   PetscScalar    *leafVals = NULL, *rootVals = NULL;
3272:   PetscSF         coarseToFineEmbedded;

3274:   PetscFunctionBegin;
3275:   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
3276:   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
3277:   PetscCall(DMGetLocalSection(fine, &localFine));
3278:   PetscCall(DMGetGlobalSection(fine, &globalFine));
3279:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec));
3280:   PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF));
3281:   PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
3282:   { /* winnow fine points that don't have global dofs out of the sf */
3283:     PetscInt        l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices;
3284:     const PetscInt *leaves;

3286:     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));
3287:     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3288:       p = leaves ? leaves[l] : l;
3289:       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
3290:       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3291:       if ((dof - cdof) > 0) {
3292:         numPointsWithDofs++;

3294:         PetscCall(PetscSectionGetDof(localFine, p, &dof));
3295:         PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1));
3296:       }
3297:     }
3298:     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
3299:     PetscCall(PetscSectionSetUp(leafIndicesSec));
3300:     PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices));
3301:     PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds));
3302:     if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals));
3303:     for (l = 0, offset = 0; l < nleaves; l++) {
3304:       p = leaves ? leaves[l] : l;
3305:       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
3306:       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3307:       if ((dof - cdof) > 0) {
3308:         PetscInt     off, gOff;
3309:         PetscInt    *pInd;
3310:         PetscScalar *pVal = NULL;

3312:         pointsWithDofs[offset++] = l;

3314:         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));

3316:         pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds;
3317:         if (gatheredValues) {
3318:           PetscInt i;

3320:           pVal = &leafVals[off + 1];
3321:           for (i = 0; i < dof; i++) pVal[i] = 0.;
3322:         }
3323:         PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));

3325:         offsets[0] = 0;
3326:         if (numFields) {
3327:           PetscInt f;

3329:           for (f = 0; f < numFields; f++) {
3330:             PetscInt fDof;
3331:             PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof));
3332:             offsets[f + 1] = fDof + offsets[f];
3333:           }
3334:           PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd));
3335:         } else {
3336:           PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd));
3337:         }
3338:         if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal));
3339:       }
3340:     }
3341:     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
3342:     PetscCall(PetscFree(pointsWithDofs));
3343:   }

3345:   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
3346:   PetscCall(DMGetLocalSection(coarse, &localCoarse));
3347:   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));

3349:   { /* there may be the case where an sf root has a parent: broadcast parents back to children */
3350:     MPI_Datatype threeInt;
3351:     PetscMPIInt  rank;
3352:     PetscInt(*parentNodeAndIdCoarse)[3];
3353:     PetscInt(*parentNodeAndIdFine)[3];
3354:     PetscInt           p, nleaves, nleavesToParents;
3355:     PetscSF            pointSF, sfToParents;
3356:     const PetscInt    *ilocal;
3357:     const PetscSFNode *iremote;
3358:     PetscSFNode       *iremoteToParents;
3359:     PetscInt          *ilocalToParents;

3361:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank));
3362:     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt));
3363:     PetscCallMPI(MPI_Type_commit(&threeInt));
3364:     PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine));
3365:     PetscCall(DMGetPointSF(coarse, &pointSF));
3366:     PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote));
3367:     for (p = pStartC; p < pEndC; p++) {
3368:       PetscInt parent, childId;
3369:       PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId));
3370:       parentNodeAndIdCoarse[p - pStartC][0] = rank;
3371:       parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC;
3372:       parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId;
3373:       if (nleaves > 0) {
3374:         PetscInt leaf = -1;

3376:         if (ilocal) {
3377:           PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf));
3378:         } else {
3379:           leaf = p - pStartC;
3380:         }
3381:         if (leaf >= 0) {
3382:           parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank;
3383:           parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index;
3384:         }
3385:       }
3386:     }
3387:     for (p = pStartF; p < pEndF; p++) {
3388:       parentNodeAndIdFine[p - pStartF][0] = -1;
3389:       parentNodeAndIdFine[p - pStartF][1] = -1;
3390:       parentNodeAndIdFine[p - pStartF][2] = -1;
3391:     }
3392:     PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
3393:     PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE));
3394:     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3395:       PetscInt dof;

3397:       PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof));
3398:       if (dof) {
3399:         PetscInt off;

3401:         PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off));
3402:         if (gatheredIndices) {
3403:           leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3404:         } else if (gatheredValues) {
3405:           leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]);
3406:         }
3407:       }
3408:       if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++;
3409:     }
3410:     PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents));
3411:     PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents));
3412:     for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) {
3413:       if (parentNodeAndIdFine[p - pStartF][0] >= 0) {
3414:         ilocalToParents[nleavesToParents]        = p - pStartF;
3415:         iremoteToParents[nleavesToParents].rank  = parentNodeAndIdFine[p - pStartF][0];
3416:         iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1];
3417:         nleavesToParents++;
3418:       }
3419:     }
3420:     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents));
3421:     PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER));
3422:     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));

3424:     coarseToFineEmbedded = sfToParents;

3426:     PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine));
3427:     PetscCallMPI(MPI_Type_free(&threeInt));
3428:   }

3430:   { /* winnow out coarse points that don't have dofs */
3431:     PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;
3432:     PetscSF  sfDofsOnly;

3434:     for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) {
3435:       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3436:       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3437:       if ((dof - cdof) > 0) numPointsWithDofs++;
3438:     }
3439:     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
3440:     for (p = pStartC, offset = 0; p < pEndC; p++) {
3441:       PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3442:       PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3443:       if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC;
3444:     }
3445:     PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly));
3446:     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3447:     PetscCall(PetscFree(pointsWithDofs));
3448:     coarseToFineEmbedded = sfDofsOnly;
3449:   }

3451:   /* communicate back to the coarse mesh which coarse points have children (that may require injection) */
3452:   PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees));
3453:   PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees));
3454:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec));
3455:   PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC));
3456:   for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC]));
3457:   PetscCall(PetscSectionSetUp(multiRootSec));
3458:   PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti));
3459:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec));
3460:   { /* distribute the leaf section */
3461:     PetscSF   multi, multiInv, indicesSF;
3462:     PetscInt *remoteOffsets, numRootIndices;

3464:     PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi));
3465:     PetscCall(PetscSFCreateInverseSF(multi, &multiInv));
3466:     PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec));
3467:     PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF));
3468:     PetscCall(PetscFree(remoteOffsets));
3469:     PetscCall(PetscSFDestroy(&multiInv));
3470:     PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices));
3471:     if (gatheredIndices) {
3472:       PetscCall(PetscMalloc1(numRootIndices, &rootInds));
3473:       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3474:       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE));
3475:     }
3476:     if (gatheredValues) {
3477:       PetscCall(PetscMalloc1(numRootIndices, &rootVals));
3478:       PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3479:       PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE));
3480:     }
3481:     PetscCall(PetscSFDestroy(&indicesSF));
3482:   }
3483:   PetscCall(PetscSectionDestroy(&leafIndicesSec));
3484:   PetscCall(PetscFree(leafInds));
3485:   PetscCall(PetscFree(leafVals));
3486:   PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3487:   *rootMultiSec = multiRootSec;
3488:   *multiLeafSec = rootIndicesSec;
3489:   if (gatheredIndices) *gatheredIndices = rootInds;
3490:   if (gatheredValues) *gatheredValues = rootVals;
3491:   PetscFunctionReturn(PETSC_SUCCESS);
3492: }

3494: PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat)
3495: {
3496:   DM             refTree;
3497:   PetscSection   multiRootSec, rootIndicesSec;
3498:   PetscSection   globalCoarse, globalFine;
3499:   PetscSection   localCoarse, localFine;
3500:   PetscSection   cSecRef;
3501:   PetscInt      *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd;
3502:   Mat            injRef;
3503:   PetscInt       numFields, maxDof;
3504:   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
3505:   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
3506:   PetscLayout    rowMap, colMap;
3507:   PetscInt       rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO;
3508:   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */

3510:   PetscFunctionBegin;

3512:   /* get the templates for the fine-to-coarse injection from the reference tree */
3513:   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
3514:   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
3515:   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
3516:   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));

3518:   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
3519:   PetscCall(DMGetLocalSection(fine, &localFine));
3520:   PetscCall(DMGetGlobalSection(fine, &globalFine));
3521:   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
3522:   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
3523:   PetscCall(DMGetLocalSection(coarse, &localCoarse));
3524:   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
3525:   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
3526:   {
3527:     PetscInt maxFields = PetscMax(1, numFields) + 1;
3528:     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
3529:   }

3531:   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL));

3533:   PetscCall(PetscMalloc1(maxDof, &parentIndices));

3535:   /* count indices */
3536:   PetscCall(MatGetLayouts(mat, &rowMap, &colMap));
3537:   PetscCall(PetscLayoutSetUp(rowMap));
3538:   PetscCall(PetscLayoutSetUp(colMap));
3539:   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
3540:   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
3541:   PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO));
3542:   for (p = pStartC; p < pEndC; p++) {
3543:     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;

3545:     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3546:     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3547:     if ((dof - cdof) <= 0) continue;
3548:     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));

3550:     rowOffsets[0]  = 0;
3551:     offsetsCopy[0] = 0;
3552:     if (numFields) {
3553:       PetscInt f;

3555:       for (f = 0; f < numFields; f++) {
3556:         PetscInt fDof;
3557:         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3558:         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3559:       }
3560:       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3561:     } else {
3562:       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3563:       rowOffsets[1] = offsetsCopy[0];
3564:     }

3566:     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
3567:     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3568:     leafEnd = leafStart + numLeaves;
3569:     for (l = leafStart; l < leafEnd; l++) {
3570:       PetscInt        numIndices, childId, offset;
3571:       const PetscInt *childIndices;

3573:       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
3574:       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3575:       childId      = rootIndices[offset++];
3576:       childIndices = &rootIndices[offset];
3577:       numIndices--;

3579:       if (childId == -1) { /* equivalent points: scatter */
3580:         PetscInt i;

3582:         for (i = 0; i < numIndices; i++) {
3583:           PetscInt colIndex = childIndices[i];
3584:           PetscInt rowIndex = parentIndices[i];
3585:           if (rowIndex < 0) continue;
3586:           PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse");
3587:           if (colIndex >= colStart && colIndex < colEnd) {
3588:             nnzD[rowIndex - rowStart] = 1;
3589:           } else {
3590:             nnzO[rowIndex - rowStart] = 1;
3591:           }
3592:         }
3593:       } else {
3594:         PetscInt parentId, f, lim;

3596:         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));

3598:         lim        = PetscMax(1, numFields);
3599:         offsets[0] = 0;
3600:         if (numFields) {
3601:           PetscInt f;

3603:           for (f = 0; f < numFields; f++) {
3604:             PetscInt fDof;
3605:             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));

3607:             offsets[f + 1] = fDof + offsets[f];
3608:           }
3609:         } else {
3610:           PetscInt cDof;

3612:           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3613:           offsets[1] = cDof;
3614:         }
3615:         for (f = 0; f < lim; f++) {
3616:           PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1];
3617:           PetscInt childStart = offsets[f], childEnd = offsets[f + 1];
3618:           PetscInt i, numD = 0, numO = 0;

3620:           for (i = childStart; i < childEnd; i++) {
3621:             PetscInt colIndex = childIndices[i];

3623:             if (colIndex < 0) continue;
3624:             if (colIndex >= colStart && colIndex < colEnd) {
3625:               numD++;
3626:             } else {
3627:               numO++;
3628:             }
3629:           }
3630:           for (i = parentStart; i < parentEnd; i++) {
3631:             PetscInt rowIndex = parentIndices[i];

3633:             if (rowIndex < 0) continue;
3634:             nnzD[rowIndex - rowStart] += numD;
3635:             nnzO[rowIndex - rowStart] += numO;
3636:           }
3637:         }
3638:       }
3639:     }
3640:   }
3641:   /* preallocate */
3642:   PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL));
3643:   PetscCall(PetscFree2(nnzD, nnzO));
3644:   /* insert values */
3645:   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3646:   for (p = pStartC; p < pEndC; p++) {
3647:     PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;

3649:     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3650:     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
3651:     if ((dof - cdof) <= 0) continue;
3652:     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));

3654:     rowOffsets[0]  = 0;
3655:     offsetsCopy[0] = 0;
3656:     if (numFields) {
3657:       PetscInt f;

3659:       for (f = 0; f < numFields; f++) {
3660:         PetscInt fDof;
3661:         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
3662:         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
3663:       }
3664:       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
3665:     } else {
3666:       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
3667:       rowOffsets[1] = offsetsCopy[0];
3668:     }

3670:     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
3671:     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
3672:     leafEnd = leafStart + numLeaves;
3673:     for (l = leafStart; l < leafEnd; l++) {
3674:       PetscInt        numIndices, childId, offset;
3675:       const PetscInt *childIndices;

3677:       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
3678:       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
3679:       childId      = rootIndices[offset++];
3680:       childIndices = &rootIndices[offset];
3681:       numIndices--;

3683:       if (childId == -1) { /* equivalent points: scatter */
3684:         PetscInt i;

3686:         for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES));
3687:       } else {
3688:         PetscInt parentId, f, lim;

3690:         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));

3692:         lim        = PetscMax(1, numFields);
3693:         offsets[0] = 0;
3694:         if (numFields) {
3695:           PetscInt f;

3697:           for (f = 0; f < numFields; f++) {
3698:             PetscInt fDof;
3699:             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));

3701:             offsets[f + 1] = fDof + offsets[f];
3702:           }
3703:         } else {
3704:           PetscInt cDof;

3706:           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
3707:           offsets[1] = cDof;
3708:         }
3709:         for (f = 0; f < lim; f++) {
3710:           PetscScalar    *childMat   = &childrenMats[childId - pRefStart][f][0];
3711:           PetscInt       *rowIndices = &parentIndices[rowOffsets[f]];
3712:           const PetscInt *colIndices = &childIndices[offsets[f]];

3714:           PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES));
3715:         }
3716:       }
3717:     }
3718:   }
3719:   PetscCall(PetscSectionDestroy(&multiRootSec));
3720:   PetscCall(PetscSectionDestroy(&rootIndicesSec));
3721:   PetscCall(PetscFree(parentIndices));
3722:   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
3723:   PetscCall(PetscFree(rootIndices));
3724:   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));

3726:   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
3727:   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
3728:   PetscFunctionReturn(PETSC_SUCCESS);
3729: }

3731: static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom)
3732: {
3733:   PetscSF            coarseToFineEmbedded;
3734:   PetscSection       globalCoarse, globalFine;
3735:   PetscSection       localCoarse, localFine;
3736:   PetscSection       aSec, cSec;
3737:   PetscSection       rootValuesSec;
3738:   PetscSection       leafValuesSec;
3739:   PetscScalar       *rootValues, *leafValues;
3740:   IS                 aIS;
3741:   const PetscInt    *anchors;
3742:   Mat                cMat;
3743:   PetscInt           numFields;
3744:   PetscInt           pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd;
3745:   PetscInt           aStart, aEnd, cStart, cEnd;
3746:   PetscInt          *maxChildIds;
3747:   PetscInt          *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO;
3748:   PetscFV            fv = NULL;
3749:   PetscInt           dim, numFVcomps = -1, fvField = -1;
3750:   DM                 cellDM = NULL, gradDM = NULL;
3751:   const PetscScalar *cellGeomArray = NULL;
3752:   const PetscScalar *gradArray     = NULL;

3754:   PetscFunctionBegin;
3755:   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
3756:   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
3757:   PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd));
3758:   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
3759:   PetscCall(DMGetGlobalSection(fine, &globalFine));
3760:   PetscCall(DMGetCoordinateDim(coarse, &dim));
3761:   { /* winnow fine points that don't have global dofs out of the sf */
3762:     PetscInt        nleaves, l;
3763:     const PetscInt *leaves;
3764:     PetscInt        dof, cdof, numPointsWithDofs, offset, *pointsWithDofs;

3766:     PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL));

3768:     for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) {
3769:       PetscInt p = leaves ? leaves[l] : l;

3771:       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
3772:       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3773:       if ((dof - cdof) > 0) numPointsWithDofs++;
3774:     }
3775:     PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs));
3776:     for (l = 0, offset = 0; l < nleaves; l++) {
3777:       PetscInt p = leaves ? leaves[l] : l;

3779:       PetscCall(PetscSectionGetDof(globalFine, p, &dof));
3780:       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof));
3781:       if ((dof - cdof) > 0) pointsWithDofs[offset++] = l;
3782:     }
3783:     PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded));
3784:     PetscCall(PetscFree(pointsWithDofs));
3785:   }
3786:   /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */
3787:   PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds));
3788:   for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2;
3789:   PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));
3790:   PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX));

3792:   PetscCall(DMGetLocalSection(coarse, &localCoarse));
3793:   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));

3795:   PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS));
3796:   PetscCall(ISGetIndices(aIS, &anchors));
3797:   PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));

3799:   PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL));
3800:   PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd));

3802:   /* create sections that will send to children the indices and matrices they will need to construct the interpolator */
3803:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec));
3804:   PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC));
3805:   PetscCall(PetscSectionGetNumFields(localCoarse, &numFields));
3806:   {
3807:     PetscInt maxFields = PetscMax(1, numFields) + 1;
3808:     PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO));
3809:   }
3810:   if (grad) {
3811:     PetscInt i;

3813:     PetscCall(VecGetDM(cellGeom, &cellDM));
3814:     PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray));
3815:     PetscCall(VecGetDM(grad, &gradDM));
3816:     PetscCall(VecGetArrayRead(grad, &gradArray));
3817:     for (i = 0; i < PetscMax(1, numFields); i++) {
3818:       PetscObject  obj;
3819:       PetscClassId id;

3821:       PetscCall(DMGetField(coarse, i, NULL, &obj));
3822:       PetscCall(PetscObjectGetClassId(obj, &id));
3823:       if (id == PETSCFV_CLASSID) {
3824:         fv = (PetscFV)obj;
3825:         PetscCall(PetscFVGetNumComponents(fv, &numFVcomps));
3826:         fvField = i;
3827:         break;
3828:       }
3829:     }
3830:   }

3832:   for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */
3833:     PetscInt dof;
3834:     PetscInt maxChildId = maxChildIds[p - pStartC];
3835:     PetscInt numValues  = 0;

3837:     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
3838:     if (dof < 0) dof = -(dof + 1);
3839:     offsets[0]    = 0;
3840:     newOffsets[0] = 0;
3841:     if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */
3842:       PetscInt *closure = NULL, closureSize, cl;

3844:       PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
3845:       for (cl = 0; cl < closureSize; cl++) { /* get the closure */
3846:         PetscInt c = closure[2 * cl], clDof;

3848:         PetscCall(PetscSectionGetDof(localCoarse, c, &clDof));
3849:         numValues += clDof;
3850:       }
3851:       PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure));
3852:     } else if (maxChildId == -1) {
3853:       PetscCall(PetscSectionGetDof(localCoarse, p, &numValues));
3854:     }
3855:     /* we will pack the column indices with the field offsets */
3856:     if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) {
3857:       /* also send the centroid, and the gradient */
3858:       numValues += dim * (1 + numFVcomps);
3859:     }
3860:     PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues));
3861:   }
3862:   PetscCall(PetscSectionSetUp(rootValuesSec));
3863:   {
3864:     PetscInt           numRootValues;
3865:     const PetscScalar *coarseArray;

3867:     PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues));
3868:     PetscCall(PetscMalloc1(numRootValues, &rootValues));
3869:     PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray));
3870:     for (p = pStartC; p < pEndC; p++) {
3871:       PetscInt     numValues;
3872:       PetscInt     pValOff;
3873:       PetscScalar *pVal;
3874:       PetscInt     maxChildId = maxChildIds[p - pStartC];

3876:       PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues));
3877:       if (!numValues) continue;
3878:       PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff));
3879:       pVal = &(rootValues[pValOff]);
3880:       if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */
3881:         PetscInt closureSize = numValues;
3882:         PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal));
3883:         if (grad && p >= cellStart && p < cellEnd) {
3884:           PetscFVCellGeom *cg;
3885:           PetscScalar     *gradVals = NULL;
3886:           PetscInt         i;

3888:           pVal += (numValues - dim * (1 + numFVcomps));

3890:           PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg));
3891:           for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i];
3892:           pVal += dim;
3893:           PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals));
3894:           for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i];
3895:         }
3896:       } else if (maxChildId == -1) {
3897:         PetscInt lDof, lOff, i;

3899:         PetscCall(PetscSectionGetDof(localCoarse, p, &lDof));
3900:         PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff));
3901:         for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i];
3902:       }
3903:     }
3904:     PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray));
3905:     PetscCall(PetscFree(maxChildIds));
3906:   }
3907:   {
3908:     PetscSF   valuesSF;
3909:     PetscInt *remoteOffsetsValues, numLeafValues;

3911:     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec));
3912:     PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec));
3913:     PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF));
3914:     PetscCall(PetscSFDestroy(&coarseToFineEmbedded));
3915:     PetscCall(PetscFree(remoteOffsetsValues));
3916:     PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues));
3917:     PetscCall(PetscMalloc1(numLeafValues, &leafValues));
3918:     PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
3919:     PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE));
3920:     PetscCall(PetscSFDestroy(&valuesSF));
3921:     PetscCall(PetscFree(rootValues));
3922:     PetscCall(PetscSectionDestroy(&rootValuesSec));
3923:   }
3924:   PetscCall(DMGetLocalSection(fine, &localFine));
3925:   {
3926:     PetscInt       maxDof;
3927:     PetscInt      *rowIndices;
3928:     DM             refTree;
3929:     PetscInt     **refPointFieldN;
3930:     PetscScalar ***refPointFieldMats;
3931:     PetscSection   refConSec, refAnSec;
3932:     PetscInt       pRefStart, pRefEnd, leafStart, leafEnd;
3933:     PetscScalar   *pointWork;

3935:     PetscCall(PetscSectionGetMaxDof(localFine, &maxDof));
3936:     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
3937:     PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
3938:     PetscCall(DMPlexGetReferenceTree(fine, &refTree));
3939:     PetscCall(DMCopyDisc(fine, refTree));
3940:     PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
3941:     PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL));
3942:     PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL));
3943:     PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd));
3944:     PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd));
3945:     PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd));
3946:     for (p = leafStart; p < leafEnd; p++) {
3947:       PetscInt           gDof, gcDof, gOff, lDof;
3948:       PetscInt           numValues, pValOff;
3949:       PetscInt           childId;
3950:       const PetscScalar *pVal;
3951:       const PetscScalar *fvGradData = NULL;

3953:       PetscCall(PetscSectionGetDof(globalFine, p, &gDof));
3954:       PetscCall(PetscSectionGetDof(localFine, p, &lDof));
3955:       PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof));
3956:       if ((gDof - gcDof) <= 0) continue;
3957:       PetscCall(PetscSectionGetOffset(globalFine, p, &gOff));
3958:       PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues));
3959:       if (!numValues) continue;
3960:       PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff));
3961:       pVal              = &leafValues[pValOff];
3962:       offsets[0]        = 0;
3963:       offsetsCopy[0]    = 0;
3964:       newOffsets[0]     = 0;
3965:       newOffsetsCopy[0] = 0;
3966:       childId           = cids[p - pStartF];
3967:       if (numFields) {
3968:         PetscInt f;
3969:         for (f = 0; f < numFields; f++) {
3970:           PetscInt rowDof;

3972:           PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof));
3973:           offsets[f + 1]     = offsets[f] + rowDof;
3974:           offsetsCopy[f + 1] = offsets[f + 1];
3975:           /* TODO: closure indices */
3976:           newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]);
3977:         }
3978:         PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices));
3979:       } else {
3980:         offsets[0]    = 0;
3981:         offsets[1]    = lDof;
3982:         newOffsets[0] = 0;
3983:         newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0];
3984:         PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices));
3985:       }
3986:       if (childId == -1) { /* no child interpolation: one nnz per */
3987:         PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES));
3988:       } else {
3989:         PetscInt f;

3991:         if (grad && p >= cellStart && p < cellEnd) {
3992:           numValues -= (dim * (1 + numFVcomps));
3993:           fvGradData = &pVal[numValues];
3994:         }
3995:         for (f = 0; f < PetscMax(1, numFields); f++) {
3996:           const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f];
3997:           PetscInt           numRows  = offsets[f + 1] - offsets[f];
3998:           PetscInt           numCols  = newOffsets[f + 1] - newOffsets[f];
3999:           const PetscScalar *cVal     = &pVal[newOffsets[f]];
4000:           PetscScalar       *rVal     = &pointWork[offsets[f]];
4001:           PetscInt           i, j;

4003: #if 0
4004:           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));
4005: #endif
4006:           for (i = 0; i < numRows; i++) {
4007:             PetscScalar val = 0.;
4008:             for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j];
4009:             rVal[i] = val;
4010:           }
4011:           if (f == fvField && p >= cellStart && p < cellEnd) {
4012:             PetscReal          centroid[3];
4013:             PetscScalar        diff[3];
4014:             const PetscScalar *parentCentroid = &fvGradData[0];
4015:             const PetscScalar *gradient       = &fvGradData[dim];

4017:             PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL));
4018:             for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i];
4019:             for (i = 0; i < numFVcomps; i++) {
4020:               PetscScalar val = 0.;

4022:               for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j];
4023:               rVal[i] += val;
4024:             }
4025:           }
4026:           PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES));
4027:         }
4028:       }
4029:     }
4030:     PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN));
4031:     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork));
4032:     PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices));
4033:   }
4034:   PetscCall(PetscFree(leafValues));
4035:   PetscCall(PetscSectionDestroy(&leafValuesSec));
4036:   PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO));
4037:   PetscCall(ISRestoreIndices(aIS, &anchors));
4038:   PetscFunctionReturn(PETSC_SUCCESS);
4039: }

4041: static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids)
4042: {
4043:   DM             refTree;
4044:   PetscSection   multiRootSec, rootIndicesSec;
4045:   PetscSection   globalCoarse, globalFine;
4046:   PetscSection   localCoarse, localFine;
4047:   PetscSection   cSecRef;
4048:   PetscInt      *parentIndices, pRefStart, pRefEnd;
4049:   PetscScalar   *rootValues, *parentValues;
4050:   Mat            injRef;
4051:   PetscInt       numFields, maxDof;
4052:   PetscInt       pStartC, pEndC, pStartF, pEndF, p;
4053:   PetscInt      *offsets, *offsetsCopy, *rowOffsets;
4054:   PetscLayout    rowMap, colMap;
4055:   PetscInt       rowStart, rowEnd, colStart, colEnd;
4056:   PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */

4058:   PetscFunctionBegin;

4060:   /* get the templates for the fine-to-coarse injection from the reference tree */
4061:   PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
4062:   PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
4063:   PetscCall(DMPlexGetReferenceTree(coarse, &refTree));
4064:   PetscCall(DMCopyDisc(coarse, refTree));
4065:   PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL));
4066:   PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd));
4067:   PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef));

4069:   PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF));
4070:   PetscCall(DMGetLocalSection(fine, &localFine));
4071:   PetscCall(DMGetGlobalSection(fine, &globalFine));
4072:   PetscCall(PetscSectionGetNumFields(localFine, &numFields));
4073:   PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC));
4074:   PetscCall(DMGetLocalSection(coarse, &localCoarse));
4075:   PetscCall(DMGetGlobalSection(coarse, &globalCoarse));
4076:   PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof));
4077:   {
4078:     PetscInt maxFields = PetscMax(1, numFields) + 1;
4079:     PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets));
4080:   }

4082:   PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues));

4084:   PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues));

4086:   /* count indices */
4087:   PetscCall(VecGetLayout(vecFine, &colMap));
4088:   PetscCall(VecGetLayout(vecCoarse, &rowMap));
4089:   PetscCall(PetscLayoutSetUp(rowMap));
4090:   PetscCall(PetscLayoutSetUp(colMap));
4091:   PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd));
4092:   PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd));
4093:   /* insert values */
4094:   PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4095:   for (p = pStartC; p < pEndC; p++) {
4096:     PetscInt  numLeaves, leafStart, leafEnd, l, dof, cdof, gOff;
4097:     PetscBool contribute = PETSC_FALSE;

4099:     PetscCall(PetscSectionGetDof(globalCoarse, p, &dof));
4100:     PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof));
4101:     if ((dof - cdof) <= 0) continue;
4102:     PetscCall(PetscSectionGetDof(localCoarse, p, &dof));
4103:     PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff));

4105:     rowOffsets[0]  = 0;
4106:     offsetsCopy[0] = 0;
4107:     if (numFields) {
4108:       PetscInt f;

4110:       for (f = 0; f < numFields; f++) {
4111:         PetscInt fDof;
4112:         PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof));
4113:         rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f];
4114:       }
4115:       PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices));
4116:     } else {
4117:       PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices));
4118:       rowOffsets[1] = offsetsCopy[0];
4119:     }

4121:     PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves));
4122:     PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart));
4123:     leafEnd = leafStart + numLeaves;
4124:     for (l = 0; l < dof; l++) parentValues[l] = 0.;
4125:     for (l = leafStart; l < leafEnd; l++) {
4126:       PetscInt           numIndices, childId, offset;
4127:       const PetscScalar *childValues;

4129:       PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices));
4130:       PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset));
4131:       childId     = (PetscInt)PetscRealPart(rootValues[offset++]);
4132:       childValues = &rootValues[offset];
4133:       numIndices--;

4135:       if (childId == -2) { /* skip */
4136:         continue;
4137:       } else if (childId == -1) { /* equivalent points: scatter */
4138:         PetscInt m;

4140:         contribute = PETSC_TRUE;
4141:         for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m];
4142:       } else { /* contributions from children: sum with injectors from reference tree */
4143:         PetscInt parentId, f, lim;

4145:         contribute = PETSC_TRUE;
4146:         PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL));

4148:         lim        = PetscMax(1, numFields);
4149:         offsets[0] = 0;
4150:         if (numFields) {
4151:           PetscInt f;

4153:           for (f = 0; f < numFields; f++) {
4154:             PetscInt fDof;
4155:             PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof));

4157:             offsets[f + 1] = fDof + offsets[f];
4158:           }
4159:         } else {
4160:           PetscInt cDof;

4162:           PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof));
4163:           offsets[1] = cDof;
4164:         }
4165:         for (f = 0; f < lim; f++) {
4166:           PetscScalar       *childMat = &childrenMats[childId - pRefStart][f][0];
4167:           PetscInt           n        = offsets[f + 1] - offsets[f];
4168:           PetscInt           m        = rowOffsets[f + 1] - rowOffsets[f];
4169:           PetscInt           i, j;
4170:           const PetscScalar *colValues = &childValues[offsets[f]];

4172:           for (i = 0; i < m; i++) {
4173:             PetscScalar val = 0.;
4174:             for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j];
4175:             parentValues[rowOffsets[f] + i] += val;
4176:           }
4177:         }
4178:       }
4179:     }
4180:     if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES));
4181:   }
4182:   PetscCall(PetscSectionDestroy(&multiRootSec));
4183:   PetscCall(PetscSectionDestroy(&rootIndicesSec));
4184:   PetscCall(PetscFree2(parentIndices, parentValues));
4185:   PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats));
4186:   PetscCall(PetscFree(rootValues));
4187:   PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets));
4188:   PetscFunctionReturn(PETSC_SUCCESS);
4189: }

4191: /*@
4192:   DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening
4193:   that can be represented by a common reference tree used by both.  This routine can be used for a combination of
4194:   coarsening and refinement at the same time.

4196:   Collective

4198:   Input Parameters:
4199: + dmIn        - The `DMPLEX` mesh for the input vector
4200: . dmOut        - The second `DMPLEX` mesh
4201: . vecIn       - The input vector
4202: . sfRefine    - A star forest indicating points in the mesh `dmIn` (roots in the star forest) that are parents to points in
4203:                 the mesh `dmOut` (leaves in the star forest), i.e. where `dmOut` is more refined than `dmIn`
4204: . sfCoarsen   - A star forest indicating points in the mesh `dmOut` (roots in the star forest) that are parents to points in
4205:                 the mesh `dmIn` (leaves in the star forest), i.e. where `dmOut` is more coarsened than `dmIn`
4206: . cidsRefine  - The childIds of the points in `dmOut`.  These childIds relate back to the reference tree: childid[j] = k implies
4207:                 that mesh point j of `dmOut` was refined from a point in `dmIn` just as the mesh point k in the reference
4208:                 tree was refined from its parent.  childid[j] = -1 indicates that the point j in `dmOut` is exactly
4209:                 equivalent to its root in `dmIn`, so no interpolation is necessary.  childid[j] = -2 indicates that this
4210:                 point j in `dmOut` is not a leaf of `sfRefine`.
4211: . cidsCoarsen - The childIds of the points in `dmIn`.  These childIds relate back to the reference tree: childid[j] = k implies
4212:                 that mesh point j of dmIn coarsens to a point in `dmOut` just as the mesh point k in the reference
4213:                 tree coarsens to its parent.  childid[j] = -2 indicates that point j in `dmOut` is not a leaf in `sfCoarsen`.
4214: . useBCs      - `PETSC_TRUE` indicates that boundary values should be inserted into `vecIn` before transfer.
4215: - time        - Used if boundary values are time dependent.

4217:   Output Parameter:
4218: . vecOut      - Using interpolation and injection operators calculated on the reference tree, the transferred
4219:                 projection of `vecIn` from `dmIn` to `dmOut`.  Note that any field discretized with a `PetscFV` finite volume
4220:                 method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4221:                 coarse points to fine points.

4223:   Level: developer

4225: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4226: @*/
4227: PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4228: {
4229:   PetscFunctionBegin;
4230:   PetscCall(VecSet(vecOut, 0.0));
4231:   if (sfRefine) {
4232:     Vec vecInLocal;
4233:     DM  dmGrad   = NULL;
4234:     Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;

4236:     PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
4237:     PetscCall(VecSet(vecInLocal, 0.0));
4238:     {
4239:       PetscInt numFields, i;

4241:       PetscCall(DMGetNumFields(dmIn, &numFields));
4242:       for (i = 0; i < numFields; i++) {
4243:         PetscObject  obj;
4244:         PetscClassId classid;

4246:         PetscCall(DMGetField(dmIn, i, NULL, &obj));
4247:         PetscCall(PetscObjectGetClassId(obj, &classid));
4248:         if (classid == PETSCFV_CLASSID) {
4249:           PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
4250:           break;
4251:         }
4252:       }
4253:     }
4254:     if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
4255:     PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
4256:     PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
4257:     if (dmGrad) {
4258:       PetscCall(DMGetGlobalVector(dmGrad, &grad));
4259:       PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
4260:     }
4261:     PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
4262:     PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
4263:     if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4264:   }
4265:   if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
4266:   PetscCall(VecAssemblyBegin(vecOut));
4267:   PetscCall(VecAssemblyEnd(vecOut));
4268:   PetscFunctionReturn(PETSC_SUCCESS);
4269: }