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 Parameters:
41: . dm - The `DMPLEX` object
43: Output Parameters:
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 oreintation 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 Parameters:
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 on dm
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 on dm
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, §ion));
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 on dmIn
4198: Input Parameters:
4199: + dmIn - The `DMPLEX` mesh for the input vector
4200: . vecIn - The input vector
4201: . sfRefine - A star forest indicating points in the mesh dmIn (roots in the star forest) that are parents to points in
4202: the mesh dmOut (leaves in the star forest), i.e. where dmOut is more refined than dmIn
4203: . sfCoarsen - A star forest indicating points in the mesh dmOut (roots in the star forest) that are parents to points in
4204: the mesh dmIn (leaves in the star forest), i.e. where dmOut is more coarsened than dmIn
4205: . cidsRefine - The childIds of the points in dmOut. These childIds relate back to the reference tree: childid[j] = k implies
4206: that mesh point j of dmOut was refined from a point in dmIn just as the mesh point k in the reference
4207: tree was refined from its parent. childid[j] = -1 indicates that the point j in dmOut is exactly
4208: equivalent to its root in dmIn, so no interpolation is necessary. childid[j] = -2 indicates that this
4209: point j in dmOut is not a leaf of sfRefine.
4210: . cidsCoarsen - The childIds of the points in dmIn. These childIds relate back to the reference tree: childid[j] = k implies
4211: that mesh point j of dmIn coarsens to a point in dmOut just as the mesh point k in the reference
4212: tree coarsens to its parent. childid[j] = -2 indicates that point j in dmOut is not a leaf in sfCoarsen.
4213: . useBCs - PETSC_TRUE indicates that boundary values should be inserted into vecIn before transfer.
4214: - time - Used if boundary values are time dependent.
4216: Output Parameters:
4217: . vecOut - Using interpolation and injection operators calculated on the reference tree, the transferred
4218: projection of vecIn from dmIn to dmOut. Note that any field discretized with a `PetscFV` finite volume
4219: method that uses gradient reconstruction will use reconstructed gradients when interpolating from
4220: coarse points to fine points.
4222: Level: developer
4224: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()`
4225: @*/
4226: PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time)
4227: {
4228: PetscFunctionBegin;
4229: PetscCall(VecSet(vecOut, 0.0));
4230: if (sfRefine) {
4231: Vec vecInLocal;
4232: DM dmGrad = NULL;
4233: Vec faceGeom = NULL, cellGeom = NULL, grad = NULL;
4235: PetscCall(DMGetLocalVector(dmIn, &vecInLocal));
4236: PetscCall(VecSet(vecInLocal, 0.0));
4237: {
4238: PetscInt numFields, i;
4240: PetscCall(DMGetNumFields(dmIn, &numFields));
4241: for (i = 0; i < numFields; i++) {
4242: PetscObject obj;
4243: PetscClassId classid;
4245: PetscCall(DMGetField(dmIn, i, NULL, &obj));
4246: PetscCall(PetscObjectGetClassId(obj, &classid));
4247: if (classid == PETSCFV_CLASSID) {
4248: PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad));
4249: break;
4250: }
4251: }
4252: }
4253: if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL));
4254: PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal));
4255: PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal));
4256: if (dmGrad) {
4257: PetscCall(DMGetGlobalVector(dmGrad, &grad));
4258: PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad));
4259: }
4260: PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom));
4261: PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal));
4262: if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
4263: }
4264: if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen));
4265: PetscCall(VecAssemblyBegin(vecOut));
4266: PetscCall(VecAssemblyEnd(vecOut));
4267: PetscFunctionReturn(PETSC_SUCCESS);
4268: }