Actual source code: plex.c
1: #include <petsc/private/dmpleximpl.h>
2: #include <petsc/private/dmlabelimpl.h>
3: #include <petsc/private/isimpl.h>
4: #include <petsc/private/vecimpl.h>
5: #include <petsc/private/glvisvecimpl.h>
6: #include <petscsf.h>
7: #include <petscds.h>
8: #include <petscdraw.h>
9: #include <petscdmfield.h>
10: #include <petscdmplextransform.h>
12: /* Logging support */
13: PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad;
14: PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate;
16: PetscBool Plexcite = PETSC_FALSE;
17: const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n"
18: "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n"
19: "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n"
20: "journal = {SIAM Journal on Scientific Computing},\n"
21: "volume = {38},\n"
22: "number = {5},\n"
23: "pages = {S143--S155},\n"
24: "eprint = {http://arxiv.org/abs/1506.07749},\n"
25: "doi = {10.1137/15M1026092},\n"
26: "year = {2016},\n"
27: "petsc_uses={DMPlex},\n}\n";
29: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
31: /*@
32: DMPlexIsSimplex - Is the first cell in this mesh a simplex?
34: Input Parameter:
35: . dm - The `DMPLEX` object
37: Output Parameter:
38: . simplex - Flag checking for a simplex
40: Level: intermediate
42: Note:
43: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
44: If the mesh has no cells, this returns `PETSC_FALSE`.
46: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()`
47: @*/
48: PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
49: {
50: DMPolytopeType ct;
51: PetscInt cStart, cEnd;
53: PetscFunctionBegin;
54: PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
55: if (cEnd <= cStart) {
56: *simplex = PETSC_FALSE;
57: PetscFunctionReturn(PETSC_SUCCESS);
58: }
59: PetscCall(DMPlexGetCellType(dm, cStart, &ct));
60: *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
61: PetscFunctionReturn(PETSC_SUCCESS);
62: }
64: /*@
65: DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
67: Input Parameters:
68: + dm - The `DMPLEX` object
69: - height - The cell height in the Plex, 0 is the default
71: Output Parameters:
72: + cStart - The first "normal" cell
73: - cEnd - The upper bound on "normal"" cells
75: Level: developer
77: Note:
78: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
80: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()`
81: @*/
82: PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
83: {
84: DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
85: PetscInt cS, cE, c;
87: PetscFunctionBegin;
88: PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE));
89: for (c = cS; c < cE; ++c) {
90: DMPolytopeType cct;
92: PetscCall(DMPlexGetCellType(dm, c, &cct));
93: if ((PetscInt)cct < 0) break;
94: switch (cct) {
95: case DM_POLYTOPE_POINT:
96: case DM_POLYTOPE_SEGMENT:
97: case DM_POLYTOPE_TRIANGLE:
98: case DM_POLYTOPE_QUADRILATERAL:
99: case DM_POLYTOPE_TETRAHEDRON:
100: case DM_POLYTOPE_HEXAHEDRON:
101: ct = cct;
102: break;
103: default:
104: break;
105: }
106: if (ct != DM_POLYTOPE_UNKNOWN) break;
107: }
108: if (ct != DM_POLYTOPE_UNKNOWN) {
109: DMLabel ctLabel;
111: PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
112: PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE));
113: // Reset label for fast lookup
114: PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
115: }
116: if (cStart) *cStart = cS;
117: if (cEnd) *cEnd = cE;
118: PetscFunctionReturn(PETSC_SUCCESS);
119: }
121: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
122: {
123: PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
124: PetscInt vcdof[2] = {0, 0}, globalvcdof[2];
126: PetscFunctionBegin;
127: *ft = PETSC_VTK_INVALID;
128: PetscCall(DMGetCoordinateDim(dm, &cdim));
129: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
130: PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
131: PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
132: if (field >= 0) {
133: if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
134: if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
135: } else {
136: if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
137: if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
138: }
139: PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
140: if (globalvcdof[0]) {
141: *sStart = vStart;
142: *sEnd = vEnd;
143: if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
144: else *ft = PETSC_VTK_POINT_FIELD;
145: } else if (globalvcdof[1]) {
146: *sStart = cStart;
147: *sEnd = cEnd;
148: if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
149: else *ft = PETSC_VTK_CELL_FIELD;
150: } else {
151: if (field >= 0) {
152: const char *fieldname;
154: PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
155: PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
156: } else {
157: PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
158: }
159: }
160: PetscFunctionReturn(PETSC_SUCCESS);
161: }
163: /*@
164: DMPlexVecView1D - Plot many 1D solutions on the same line graph
166: Collective
168: Input Parameters:
169: + dm - The `DMPLEX` object
170: . n - The number of vectors
171: . u - The array of local vectors
172: - viewer - The `PetscViewer`
174: Level: advanced
176: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()`
177: @*/
178: PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
179: {
180: PetscDS ds;
181: PetscDraw draw = NULL;
182: PetscDrawLG lg;
183: Vec coordinates;
184: const PetscScalar *coords, **sol;
185: PetscReal *vals;
186: PetscInt *Nc;
187: PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v;
188: char **names;
190: PetscFunctionBegin;
191: PetscCall(DMGetDS(dm, &ds));
192: PetscCall(PetscDSGetNumFields(ds, &Nf));
193: PetscCall(PetscDSGetTotalComponents(ds, &Nl));
194: PetscCall(PetscDSGetComponents(ds, &Nc));
196: PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
197: if (!draw) PetscFunctionReturn(PETSC_SUCCESS);
198: PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg));
200: PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals));
201: for (i = 0, l = 0; i < n; ++i) {
202: const char *vname;
204: PetscCall(PetscObjectGetName((PetscObject)u[i], &vname));
205: for (f = 0; f < Nf; ++f) {
206: PetscObject disc;
207: const char *fname;
208: char tmpname[PETSC_MAX_PATH_LEN];
210: PetscCall(PetscDSGetDiscretization(ds, f, &disc));
211: /* TODO Create names for components */
212: for (c = 0; c < Nc[f]; ++c, ++l) {
213: PetscCall(PetscObjectGetName(disc, &fname));
214: PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname)));
215: PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname)));
216: PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname)));
217: PetscCall(PetscStrallocpy(tmpname, &names[l]));
218: }
219: }
220: }
221: PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names));
222: /* Just add P_1 support for now */
223: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
224: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
225: PetscCall(VecGetArrayRead(coordinates, &coords));
226: for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
227: for (v = vStart; v < vEnd; ++v) {
228: PetscScalar *x, *svals;
230: PetscCall(DMPlexPointLocalRead(dm, v, coords, &x));
231: for (i = 0; i < n; ++i) {
232: PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
233: for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
234: }
235: PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
236: }
237: PetscCall(VecRestoreArrayRead(coordinates, &coords));
238: for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
239: for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l]));
240: PetscCall(PetscFree3(sol, names, vals));
242: PetscCall(PetscDrawLGDraw(lg));
243: PetscCall(PetscDrawLGDestroy(&lg));
244: PetscFunctionReturn(PETSC_SUCCESS);
245: }
247: static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
248: {
249: DM dm;
251: PetscFunctionBegin;
252: PetscCall(VecGetDM(u, &dm));
253: PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
254: PetscFunctionReturn(PETSC_SUCCESS);
255: }
257: static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
258: {
259: DM dm;
260: PetscSection s;
261: PetscDraw draw, popup;
262: DM cdm;
263: PetscSection coordSection;
264: Vec coordinates;
265: const PetscScalar *array;
266: PetscReal lbound[3], ubound[3];
267: PetscReal vbound[2], time;
268: PetscBool flg;
269: PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
270: const char *name;
271: char title[PETSC_MAX_PATH_LEN];
273: PetscFunctionBegin;
274: PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
275: PetscCall(VecGetDM(v, &dm));
276: PetscCall(DMGetCoordinateDim(dm, &dim));
277: PetscCall(DMGetLocalSection(dm, &s));
278: PetscCall(PetscSectionGetNumFields(s, &Nf));
279: PetscCall(DMGetCoarsenLevel(dm, &level));
280: PetscCall(DMGetCoordinateDM(dm, &cdm));
281: PetscCall(DMGetLocalSection(cdm, &coordSection));
282: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
283: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
284: PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
286: PetscCall(PetscObjectGetName((PetscObject)v, &name));
287: PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));
289: PetscCall(VecGetLocalSize(coordinates, &N));
290: PetscCall(DMGetBoundingBox(dm, lbound, ubound));
291: PetscCall(PetscDrawClear(draw));
293: /* Could implement something like DMDASelectFields() */
294: for (f = 0; f < Nf; ++f) {
295: DM fdm = dm;
296: Vec fv = v;
297: IS fis;
298: char prefix[PETSC_MAX_PATH_LEN];
299: const char *fname;
301: PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
302: PetscCall(PetscSectionGetFieldName(s, f, &fname));
304: if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix)));
305: else prefix[0] = '\0';
306: if (Nf > 1) {
307: PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
308: PetscCall(VecGetSubVector(v, fis, &fv));
309: PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix)));
310: PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix)));
311: }
312: for (comp = 0; comp < Nc; ++comp, ++w) {
313: PetscInt nmax = 2;
315: PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw));
316: if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time));
317: else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time));
318: PetscCall(PetscDrawSetTitle(draw, title));
320: /* TODO Get max and min only for this component */
321: PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
322: if (!flg) {
323: PetscCall(VecMin(fv, NULL, &vbound[0]));
324: PetscCall(VecMax(fv, NULL, &vbound[1]));
325: if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
326: }
328: PetscCall(PetscDrawGetPopup(draw, &popup));
329: PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
330: PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1]));
331: PetscCall(VecGetArrayRead(fv, &array));
332: for (c = cStart; c < cEnd; ++c) {
333: PetscScalar *coords = NULL, *a = NULL;
334: const PetscScalar *coords_arr;
335: PetscBool isDG;
336: PetscInt numCoords, color[4] = {-1, -1, -1, -1};
338: PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
339: if (a) {
340: color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
341: color[1] = color[2] = color[3] = color[0];
342: } else {
343: PetscScalar *vals = NULL;
344: PetscInt numVals, va;
346: PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
347: PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals);
348: switch (numVals / Nc) {
349: case 3: /* P1 Triangle */
350: case 4: /* P1 Quadrangle */
351: for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
352: break;
353: case 6: /* P2 Triangle */
354: case 8: /* P2 Quadrangle */
355: for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]);
356: break;
357: default:
358: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc);
359: }
360: PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
361: }
362: PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
363: switch (numCoords) {
364: case 6:
365: case 12: /* Localized triangle */
366: PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]));
367: break;
368: case 8:
369: case 16: /* Localized quadrilateral */
370: PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]));
371: PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0]));
372: break;
373: default:
374: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
375: }
376: PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
377: }
378: PetscCall(VecRestoreArrayRead(fv, &array));
379: PetscCall(PetscDrawFlush(draw));
380: PetscCall(PetscDrawPause(draw));
381: PetscCall(PetscDrawSave(draw));
382: }
383: if (Nf > 1) {
384: PetscCall(VecRestoreSubVector(v, fis, &fv));
385: PetscCall(ISDestroy(&fis));
386: PetscCall(DMDestroy(&fdm));
387: }
388: }
389: PetscFunctionReturn(PETSC_SUCCESS);
390: }
392: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
393: {
394: DM dm;
395: PetscDraw draw;
396: PetscInt dim;
397: PetscBool isnull;
399: PetscFunctionBegin;
400: PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
401: PetscCall(PetscDrawIsNull(draw, &isnull));
402: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
404: PetscCall(VecGetDM(v, &dm));
405: PetscCall(DMGetCoordinateDim(dm, &dim));
406: switch (dim) {
407: case 1:
408: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));
409: break;
410: case 2:
411: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));
412: break;
413: default:
414: SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
415: }
416: PetscFunctionReturn(PETSC_SUCCESS);
417: }
419: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
420: {
421: DM dm;
422: Vec locv;
423: const char *name;
424: PetscSection section;
425: PetscInt pStart, pEnd;
426: PetscInt numFields;
427: PetscViewerVTKFieldType ft;
429: PetscFunctionBegin;
430: PetscCall(VecGetDM(v, &dm));
431: PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
432: PetscCall(PetscObjectGetName((PetscObject)v, &name));
433: PetscCall(PetscObjectSetName((PetscObject)locv, name));
434: PetscCall(VecCopy(v, locv));
435: PetscCall(DMGetLocalSection(dm, §ion));
436: PetscCall(PetscSectionGetNumFields(section, &numFields));
437: if (!numFields) {
438: PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
439: PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv));
440: } else {
441: PetscInt f;
443: for (f = 0; f < numFields; f++) {
444: PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
445: if (ft == PETSC_VTK_INVALID) continue;
446: PetscCall(PetscObjectReference((PetscObject)locv));
447: PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv));
448: }
449: PetscCall(VecDestroy(&locv));
450: }
451: PetscFunctionReturn(PETSC_SUCCESS);
452: }
454: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
455: {
456: DM dm;
457: PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns;
459: PetscFunctionBegin;
460: PetscCall(VecGetDM(v, &dm));
461: PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
462: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
463: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
464: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
465: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
466: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
467: if (isvtk || ishdf5 || isdraw || isglvis || iscgns) {
468: PetscInt i, numFields;
469: PetscObject fe;
470: PetscBool fem = PETSC_FALSE;
471: Vec locv = v;
472: const char *name;
473: PetscInt step;
474: PetscReal time;
476: PetscCall(DMGetNumFields(dm, &numFields));
477: for (i = 0; i < numFields; i++) {
478: PetscCall(DMGetField(dm, i, NULL, &fe));
479: if (fe->classid == PETSCFE_CLASSID) {
480: fem = PETSC_TRUE;
481: break;
482: }
483: }
484: if (fem) {
485: PetscObject isZero;
487: PetscCall(DMGetLocalVector(dm, &locv));
488: PetscCall(PetscObjectGetName((PetscObject)v, &name));
489: PetscCall(PetscObjectSetName((PetscObject)locv, name));
490: PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
491: PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
492: PetscCall(VecCopy(v, locv));
493: PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
494: PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
495: }
496: if (isvtk) {
497: PetscCall(VecView_Plex_Local_VTK(locv, viewer));
498: } else if (ishdf5) {
499: #if defined(PETSC_HAVE_HDF5)
500: PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
501: #else
502: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
503: #endif
504: } else if (isdraw) {
505: PetscCall(VecView_Plex_Local_Draw(locv, viewer));
506: } else if (isglvis) {
507: PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
508: PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
509: PetscCall(VecView_GLVis(locv, viewer));
510: } else if (iscgns) {
511: #if defined(PETSC_HAVE_CGNS)
512: PetscCall(VecView_Plex_Local_CGNS(locv, viewer));
513: #else
514: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
515: #endif
516: }
517: if (fem) {
518: PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
519: PetscCall(DMRestoreLocalVector(dm, &locv));
520: }
521: } else {
522: PetscBool isseq;
524: PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
525: if (isseq) PetscCall(VecView_Seq(v, viewer));
526: else PetscCall(VecView_MPI(v, viewer));
527: }
528: PetscFunctionReturn(PETSC_SUCCESS);
529: }
531: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
532: {
533: DM dm;
534: PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns;
536: PetscFunctionBegin;
537: PetscCall(VecGetDM(v, &dm));
538: PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
539: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
540: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
541: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
542: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
543: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
544: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
545: if (isvtk || isdraw || isglvis || iscgns) {
546: Vec locv;
547: PetscObject isZero;
548: const char *name;
550: PetscCall(DMGetLocalVector(dm, &locv));
551: PetscCall(PetscObjectGetName((PetscObject)v, &name));
552: PetscCall(PetscObjectSetName((PetscObject)locv, name));
553: PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
554: PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
555: PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
556: PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
557: PetscCall(VecView_Plex_Local(locv, viewer));
558: PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
559: PetscCall(DMRestoreLocalVector(dm, &locv));
560: } else if (ishdf5) {
561: #if defined(PETSC_HAVE_HDF5)
562: PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
563: #else
564: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
565: #endif
566: } else if (isexodusii) {
567: #if defined(PETSC_HAVE_EXODUSII)
568: PetscCall(VecView_PlexExodusII_Internal(v, viewer));
569: #else
570: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
571: #endif
572: } else {
573: PetscBool isseq;
575: PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
576: if (isseq) PetscCall(VecView_Seq(v, viewer));
577: else PetscCall(VecView_MPI(v, viewer));
578: }
579: PetscFunctionReturn(PETSC_SUCCESS);
580: }
582: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
583: {
584: DM dm;
585: MPI_Comm comm;
586: PetscViewerFormat format;
587: Vec v;
588: PetscBool isvtk, ishdf5;
590: PetscFunctionBegin;
591: PetscCall(VecGetDM(originalv, &dm));
592: PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm));
593: PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
594: PetscCall(PetscViewerGetFormat(viewer, &format));
595: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
596: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
597: if (format == PETSC_VIEWER_NATIVE) {
598: /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
599: /* this need a better fix */
600: if (dm->useNatural) {
601: if (dm->sfNatural) {
602: const char *vecname;
603: PetscInt n, nroots;
605: PetscCall(VecGetLocalSize(originalv, &n));
606: PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
607: if (n == nroots) {
608: PetscCall(DMPlexCreateNaturalVector(dm, &v));
609: PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
610: PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
611: PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
612: PetscCall(PetscObjectSetName((PetscObject)v, vecname));
613: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
614: } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
615: } else v = originalv;
616: } else v = originalv;
618: if (ishdf5) {
619: #if defined(PETSC_HAVE_HDF5)
620: PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
621: #else
622: SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
623: #endif
624: } else if (isvtk) {
625: SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
626: } else {
627: PetscBool isseq;
629: PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
630: if (isseq) PetscCall(VecView_Seq(v, viewer));
631: else PetscCall(VecView_MPI(v, viewer));
632: }
633: if (v != originalv) PetscCall(VecDestroy(&v));
634: PetscFunctionReturn(PETSC_SUCCESS);
635: }
637: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
638: {
639: DM dm;
640: PetscBool ishdf5;
642: PetscFunctionBegin;
643: PetscCall(VecGetDM(v, &dm));
644: PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
645: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
646: if (ishdf5) {
647: DM dmBC;
648: Vec gv;
649: const char *name;
651: PetscCall(DMGetOutputDM(dm, &dmBC));
652: PetscCall(DMGetGlobalVector(dmBC, &gv));
653: PetscCall(PetscObjectGetName((PetscObject)v, &name));
654: PetscCall(PetscObjectSetName((PetscObject)gv, name));
655: PetscCall(VecLoad_Default(gv, viewer));
656: PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
657: PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
658: PetscCall(DMRestoreGlobalVector(dmBC, &gv));
659: } else PetscCall(VecLoad_Default(v, viewer));
660: PetscFunctionReturn(PETSC_SUCCESS);
661: }
663: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
664: {
665: DM dm;
666: PetscBool ishdf5, isexodusii;
668: PetscFunctionBegin;
669: PetscCall(VecGetDM(v, &dm));
670: PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
671: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
672: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
673: if (ishdf5) {
674: #if defined(PETSC_HAVE_HDF5)
675: PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
676: #else
677: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
678: #endif
679: } else if (isexodusii) {
680: #if defined(PETSC_HAVE_EXODUSII)
681: PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
682: #else
683: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
684: #endif
685: } else PetscCall(VecLoad_Default(v, viewer));
686: PetscFunctionReturn(PETSC_SUCCESS);
687: }
689: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
690: {
691: DM dm;
692: PetscViewerFormat format;
693: PetscBool ishdf5;
695: PetscFunctionBegin;
696: PetscCall(VecGetDM(originalv, &dm));
697: PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
698: PetscCall(PetscViewerGetFormat(viewer, &format));
699: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
700: if (format == PETSC_VIEWER_NATIVE) {
701: if (dm->useNatural) {
702: if (dm->sfNatural) {
703: if (ishdf5) {
704: #if defined(PETSC_HAVE_HDF5)
705: Vec v;
706: const char *vecname;
708: PetscCall(DMPlexCreateNaturalVector(dm, &v));
709: PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
710: PetscCall(PetscObjectSetName((PetscObject)v, vecname));
711: PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
712: PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
713: PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
714: PetscCall(VecDestroy(&v));
715: #else
716: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
717: #endif
718: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
719: }
720: } else PetscCall(VecLoad_Default(originalv, viewer));
721: }
722: PetscFunctionReturn(PETSC_SUCCESS);
723: }
725: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
726: {
727: PetscSection coordSection;
728: Vec coordinates;
729: DMLabel depthLabel, celltypeLabel;
730: const char *name[4];
731: const PetscScalar *a;
732: PetscInt dim, pStart, pEnd, cStart, cEnd, c;
734: PetscFunctionBegin;
735: PetscCall(DMGetDimension(dm, &dim));
736: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
737: PetscCall(DMGetCoordinateSection(dm, &coordSection));
738: PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
739: PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
740: PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
741: PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
742: PetscCall(VecGetArrayRead(coordinates, &a));
743: name[0] = "vertex";
744: name[1] = "edge";
745: name[dim - 1] = "face";
746: name[dim] = "cell";
747: for (c = cStart; c < cEnd; ++c) {
748: PetscInt *closure = NULL;
749: PetscInt closureSize, cl, ct;
751: PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
752: PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
753: PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
754: PetscCall(PetscViewerASCIIPushTab(viewer));
755: for (cl = 0; cl < closureSize * 2; cl += 2) {
756: PetscInt point = closure[cl], depth, dof, off, d, p;
758: if ((point < pStart) || (point >= pEnd)) continue;
759: PetscCall(PetscSectionGetDof(coordSection, point, &dof));
760: if (!dof) continue;
761: PetscCall(DMLabelGetValue(depthLabel, point, &depth));
762: PetscCall(PetscSectionGetOffset(coordSection, point, &off));
763: PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
764: for (p = 0; p < dof / dim; ++p) {
765: PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
766: for (d = 0; d < dim; ++d) {
767: if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
768: PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d])));
769: }
770: PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
771: }
772: PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
773: }
774: PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
775: PetscCall(PetscViewerASCIIPopTab(viewer));
776: }
777: PetscCall(VecRestoreArrayRead(coordinates, &a));
778: PetscFunctionReturn(PETSC_SUCCESS);
779: }
781: typedef enum {
782: CS_CARTESIAN,
783: CS_POLAR,
784: CS_CYLINDRICAL,
785: CS_SPHERICAL
786: } CoordSystem;
787: const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
789: static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
790: {
791: PetscInt i;
793: PetscFunctionBegin;
794: if (dim > 3) {
795: for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i])));
796: } else {
797: PetscReal coords[3], trcoords[3] = {0., 0., 0.};
799: for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
800: switch (cs) {
801: case CS_CARTESIAN:
802: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];
803: break;
804: case CS_POLAR:
805: PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
806: trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
807: trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
808: break;
809: case CS_CYLINDRICAL:
810: PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
811: trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
812: trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
813: trcoords[2] = coords[2];
814: break;
815: case CS_SPHERICAL:
816: PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
817: trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
818: trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
819: trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
820: break;
821: }
822: for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i]));
823: }
824: PetscFunctionReturn(PETSC_SUCCESS);
825: }
827: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
828: {
829: DM_Plex *mesh = (DM_Plex *)dm->data;
830: DM cdm, cdmCell;
831: PetscSection coordSection, coordSectionCell;
832: Vec coordinates, coordinatesCell;
833: PetscViewerFormat format;
835: PetscFunctionBegin;
836: PetscCall(PetscViewerGetFormat(viewer, &format));
837: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
838: const char *name;
839: PetscInt dim, cellHeight, maxConeSize, maxSupportSize;
840: PetscInt pStart, pEnd, p, numLabels, l;
841: PetscMPIInt rank, size;
843: PetscCall(DMGetCoordinateDM(dm, &cdm));
844: PetscCall(DMGetCoordinateSection(dm, &coordSection));
845: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
846: PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
847: PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
848: PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
849: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
850: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
851: PetscCall(PetscObjectGetName((PetscObject)dm, &name));
852: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
853: PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
854: PetscCall(DMGetDimension(dm, &dim));
855: PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
856: if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
857: else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
858: if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight));
859: PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
860: PetscCall(PetscViewerASCIIPushSynchronized(viewer));
861: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
862: for (p = pStart; p < pEnd; ++p) {
863: PetscInt dof, off, s;
865: PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
866: PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
867: for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
868: }
869: PetscCall(PetscViewerFlush(viewer));
870: PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
871: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
872: for (p = pStart; p < pEnd; ++p) {
873: PetscInt dof, off, c;
875: PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
876: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
877: for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]));
878: }
879: PetscCall(PetscViewerFlush(viewer));
880: PetscCall(PetscViewerASCIIPopSynchronized(viewer));
881: if (coordSection && coordinates) {
882: CoordSystem cs = CS_CARTESIAN;
883: const PetscScalar *array, *arrayCell = NULL;
884: PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p;
885: PetscMPIInt rank;
886: const char *name;
888: PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL));
889: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
890: PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
891: PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
892: PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
893: PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
894: if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
895: pStart = PetscMin(pvStart, pcStart);
896: pEnd = PetscMax(pvEnd, pcEnd);
897: PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
898: PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
899: PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc));
900: if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs]));
902: PetscCall(VecGetArrayRead(coordinates, &array));
903: if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
904: PetscCall(PetscViewerASCIIPushSynchronized(viewer));
905: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
906: for (p = pStart; p < pEnd; ++p) {
907: PetscInt dof, off;
909: if (p >= pvStart && p < pvEnd) {
910: PetscCall(PetscSectionGetDof(coordSection, p, &dof));
911: PetscCall(PetscSectionGetOffset(coordSection, p, &off));
912: if (dof) {
913: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
914: PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
915: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
916: }
917: }
918: if (cdmCell && p >= pcStart && p < pcEnd) {
919: PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
920: PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
921: if (dof) {
922: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
923: PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
924: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
925: }
926: }
927: }
928: PetscCall(PetscViewerFlush(viewer));
929: PetscCall(PetscViewerASCIIPopSynchronized(viewer));
930: PetscCall(VecRestoreArrayRead(coordinates, &array));
931: if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
932: }
933: PetscCall(DMGetNumLabels(dm, &numLabels));
934: if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
935: for (l = 0; l < numLabels; ++l) {
936: DMLabel label;
937: PetscBool isdepth;
938: const char *name;
940: PetscCall(DMGetLabelName(dm, l, &name));
941: PetscCall(PetscStrcmp(name, "depth", &isdepth));
942: if (isdepth) continue;
943: PetscCall(DMGetLabel(dm, name, &label));
944: PetscCall(DMLabelView(label, viewer));
945: }
946: if (size > 1) {
947: PetscSF sf;
949: PetscCall(DMGetPointSF(dm, &sf));
950: PetscCall(PetscSFView(sf, viewer));
951: }
952: if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer));
953: PetscCall(PetscViewerFlush(viewer));
954: } else if (format == PETSC_VIEWER_ASCII_LATEX) {
955: const char *name, *color;
956: const char *defcolors[3] = {"gray", "orange", "green"};
957: const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
958: char lname[PETSC_MAX_PATH_LEN];
959: PetscReal scale = 2.0;
960: PetscReal tikzscale = 1.0;
961: PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
962: double tcoords[3];
963: PetscScalar *coords;
964: PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
965: PetscMPIInt rank, size;
966: char **names, **colors, **lcolors;
967: PetscBool flg, lflg;
968: PetscBT wp = NULL;
969: PetscInt pEnd, pStart;
971: PetscCall(DMGetCoordinateDM(dm, &cdm));
972: PetscCall(DMGetCoordinateSection(dm, &coordSection));
973: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
974: PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
975: PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
976: PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
977: PetscCall(DMGetDimension(dm, &dim));
978: PetscCall(DMPlexGetDepth(dm, &depth));
979: PetscCall(DMGetNumLabels(dm, &numLabels));
980: numLabels = PetscMax(numLabels, 10);
981: numColors = 10;
982: numLColors = 10;
983: PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
984: PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
985: PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
986: PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
987: for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
988: for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE;
989: n = 4;
990: PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
991: PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
992: PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
993: PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
994: PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
995: if (!useLabels) numLabels = 0;
996: PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
997: if (!useColors) {
998: numColors = 3;
999: for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
1000: }
1001: PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
1002: if (!useColors) {
1003: numLColors = 4;
1004: for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
1005: }
1006: PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
1007: plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
1008: PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
1009: PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated");
1010: if (depth < dim) plotEdges = PETSC_FALSE;
1011: PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));
1013: /* filter points with labelvalue != labeldefaultvalue */
1014: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1015: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1016: PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
1017: PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1018: if (lflg) {
1019: DMLabel lbl;
1021: PetscCall(DMGetLabel(dm, lname, &lbl));
1022: if (lbl) {
1023: PetscInt val, defval;
1025: PetscCall(DMLabelGetDefaultValue(lbl, &defval));
1026: PetscCall(PetscBTCreate(pEnd - pStart, &wp));
1027: for (c = pStart; c < pEnd; c++) {
1028: PetscInt *closure = NULL;
1029: PetscInt closureSize;
1031: PetscCall(DMLabelGetValue(lbl, c, &val));
1032: if (val == defval) continue;
1034: PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1035: for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart));
1036: PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1037: }
1038: }
1039: }
1041: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1042: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1043: PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1044: PetscCall(PetscViewerASCIIPrintf(viewer, "\
1045: \\documentclass[tikz]{standalone}\n\n\
1046: \\usepackage{pgflibraryshapes}\n\
1047: \\usetikzlibrary{backgrounds}\n\
1048: \\usetikzlibrary{arrows}\n\
1049: \\begin{document}\n"));
1050: if (size > 1) {
1051: PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1052: for (p = 0; p < size; ++p) {
1053: if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", "));
1054: PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p));
1055: }
1056: PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
1057: }
1058: if (drawHasse) {
1059: PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart));
1061: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
1062: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1));
1063: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart));
1064: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.));
1065: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
1066: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1));
1067: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.));
1068: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart));
1069: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
1070: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1));
1071: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart));
1072: PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.));
1073: }
1074: PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale));
1076: /* Plot vertices */
1077: PetscCall(VecGetArray(coordinates, &coords));
1078: PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1079: for (v = vStart; v < vEnd; ++v) {
1080: PetscInt off, dof, d;
1081: PetscBool isLabeled = PETSC_FALSE;
1083: if (wp && !PetscBTLookup(wp, v - pStart)) continue;
1084: PetscCall(PetscSectionGetDof(coordSection, v, &dof));
1085: PetscCall(PetscSectionGetOffset(coordSection, v, &off));
1086: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1087: PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof);
1088: for (d = 0; d < dof; ++d) {
1089: tcoords[d] = (double)(scale * PetscRealPart(coords[off + d]));
1090: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1091: }
1092: /* Rotate coordinates since PGF makes z point out of the page instead of up */
1093: if (dim == 3) {
1094: PetscReal tmp = tcoords[1];
1095: tcoords[1] = tcoords[2];
1096: tcoords[2] = -tmp;
1097: }
1098: for (d = 0; d < dof; ++d) {
1099: if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1100: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1101: }
1102: if (drawHasse) color = colors[0 % numColors];
1103: else color = colors[rank % numColors];
1104: for (l = 0; l < numLabels; ++l) {
1105: PetscInt val;
1106: PetscCall(DMGetLabelValue(dm, names[l], v, &val));
1107: if (val >= 0) {
1108: color = lcolors[l % numLColors];
1109: isLabeled = PETSC_TRUE;
1110: break;
1111: }
1112: }
1113: if (drawNumbers[0]) {
1114: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1115: } else if (drawColors[0]) {
1116: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
1117: } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1118: }
1119: PetscCall(VecRestoreArray(coordinates, &coords));
1120: PetscCall(PetscViewerFlush(viewer));
1121: /* Plot edges */
1122: if (plotEdges) {
1123: PetscCall(VecGetArray(coordinates, &coords));
1124: PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1125: for (e = eStart; e < eEnd; ++e) {
1126: const PetscInt *cone;
1127: PetscInt coneSize, offA, offB, dof, d;
1129: if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1130: PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
1131: PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
1132: PetscCall(DMPlexGetCone(dm, e, &cone));
1133: PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
1134: PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
1135: PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
1136: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1137: for (d = 0; d < dof; ++d) {
1138: tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d]));
1139: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1140: }
1141: /* Rotate coordinates since PGF makes z point out of the page instead of up */
1142: if (dim == 3) {
1143: PetscReal tmp = tcoords[1];
1144: tcoords[1] = tcoords[2];
1145: tcoords[2] = -tmp;
1146: }
1147: for (d = 0; d < dof; ++d) {
1148: if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1149: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1150: }
1151: if (drawHasse) color = colors[1 % numColors];
1152: else color = colors[rank % numColors];
1153: for (l = 0; l < numLabels; ++l) {
1154: PetscInt val;
1155: PetscCall(DMGetLabelValue(dm, names[l], v, &val));
1156: if (val >= 0) {
1157: color = lcolors[l % numLColors];
1158: break;
1159: }
1160: }
1161: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1162: }
1163: PetscCall(VecRestoreArray(coordinates, &coords));
1164: PetscCall(PetscViewerFlush(viewer));
1165: PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1166: }
1167: /* Plot cells */
1168: if (dim == 3 || !drawNumbers[1]) {
1169: for (e = eStart; e < eEnd; ++e) {
1170: const PetscInt *cone;
1172: if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1173: color = colors[rank % numColors];
1174: for (l = 0; l < numLabels; ++l) {
1175: PetscInt val;
1176: PetscCall(DMGetLabelValue(dm, names[l], e, &val));
1177: if (val >= 0) {
1178: color = lcolors[l % numLColors];
1179: break;
1180: }
1181: }
1182: PetscCall(DMPlexGetCone(dm, e, &cone));
1183: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1184: }
1185: } else {
1186: DMPolytopeType ct;
1188: /* Drawing a 2D polygon */
1189: for (c = cStart; c < cEnd; ++c) {
1190: if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1191: PetscCall(DMPlexGetCellType(dm, c, &ct));
1192: if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1193: const PetscInt *cone;
1194: PetscInt coneSize, e;
1196: PetscCall(DMPlexGetCone(dm, c, &cone));
1197: PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1198: for (e = 0; e < coneSize; ++e) {
1199: const PetscInt *econe;
1201: PetscCall(DMPlexGetCone(dm, cone[e], &econe));
1202: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank));
1203: }
1204: } else {
1205: PetscInt *closure = NULL;
1206: PetscInt closureSize, Nv = 0, v;
1208: PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1209: for (p = 0; p < closureSize * 2; p += 2) {
1210: const PetscInt point = closure[p];
1212: if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1213: }
1214: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1215: for (v = 0; v <= Nv; ++v) {
1216: const PetscInt vertex = closure[v % Nv];
1218: if (v > 0) {
1219: if (plotEdges) {
1220: const PetscInt *edge;
1221: PetscInt endpoints[2], ne;
1223: endpoints[0] = closure[v - 1];
1224: endpoints[1] = vertex;
1225: PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
1226: PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
1227: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
1228: PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
1229: } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1230: }
1231: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1232: }
1233: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
1234: PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1235: }
1236: }
1237: }
1238: for (c = cStart; c < cEnd; ++c) {
1239: double ccoords[3] = {0.0, 0.0, 0.0};
1240: PetscBool isLabeled = PETSC_FALSE;
1241: PetscScalar *cellCoords = NULL;
1242: const PetscScalar *array;
1243: PetscInt numCoords, cdim, d;
1244: PetscBool isDG;
1246: if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1247: PetscCall(DMGetCoordinateDim(dm, &cdim));
1248: PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1249: PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords);
1250: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1251: for (p = 0; p < numCoords / cdim; ++p) {
1252: for (d = 0; d < cdim; ++d) {
1253: tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d]));
1254: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1255: }
1256: /* Rotate coordinates since PGF makes z point out of the page instead of up */
1257: if (cdim == 3) {
1258: PetscReal tmp = tcoords[1];
1259: tcoords[1] = tcoords[2];
1260: tcoords[2] = -tmp;
1261: }
1262: for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d];
1263: }
1264: for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim);
1265: PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1266: for (d = 0; d < cdim; ++d) {
1267: if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1268: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d]));
1269: }
1270: if (drawHasse) color = colors[depth % numColors];
1271: else color = colors[rank % numColors];
1272: for (l = 0; l < numLabels; ++l) {
1273: PetscInt val;
1274: PetscCall(DMGetLabelValue(dm, names[l], c, &val));
1275: if (val >= 0) {
1276: color = lcolors[l % numLColors];
1277: isLabeled = PETSC_TRUE;
1278: break;
1279: }
1280: }
1281: if (drawNumbers[dim]) {
1282: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1283: } else if (drawColors[dim]) {
1284: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
1285: } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1286: }
1287: if (drawHasse) {
1288: color = colors[depth % numColors];
1289: PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
1290: PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
1291: PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1292: PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color));
1293: PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1295: color = colors[1 % numColors];
1296: PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
1297: PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
1298: PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1299: PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color));
1300: PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1302: color = colors[0 % numColors];
1303: PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
1304: PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
1305: PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1306: PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color));
1307: PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));
1309: for (p = pStart; p < pEnd; ++p) {
1310: const PetscInt *cone;
1311: PetscInt coneSize, cp;
1313: PetscCall(DMPlexGetCone(dm, p, &cone));
1314: PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
1315: for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank));
1316: }
1317: }
1318: PetscCall(PetscViewerFlush(viewer));
1319: PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1320: PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
1321: PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
1322: for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
1323: for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
1324: for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
1325: PetscCall(PetscFree3(names, colors, lcolors));
1326: PetscCall(PetscBTDestroy(&wp));
1327: } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
1328: Vec cown, acown;
1329: VecScatter sct;
1330: ISLocalToGlobalMapping g2l;
1331: IS gid, acis;
1332: MPI_Comm comm, ncomm = MPI_COMM_NULL;
1333: MPI_Group ggroup, ngroup;
1334: PetscScalar *array, nid;
1335: const PetscInt *idxs;
1336: PetscInt *idxs2, *start, *adjacency, *work;
1337: PetscInt64 lm[3], gm[3];
1338: PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
1339: PetscMPIInt d1, d2, rank;
1341: PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1342: PetscCallMPI(MPI_Comm_rank(comm, &rank));
1343: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1344: PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
1345: #endif
1346: if (ncomm != MPI_COMM_NULL) {
1347: PetscCallMPI(MPI_Comm_group(comm, &ggroup));
1348: PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
1349: d1 = 0;
1350: PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
1351: nid = d2;
1352: PetscCallMPI(MPI_Group_free(&ggroup));
1353: PetscCallMPI(MPI_Group_free(&ngroup));
1354: PetscCallMPI(MPI_Comm_free(&ncomm));
1355: } else nid = 0.0;
1357: /* Get connectivity */
1358: PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1359: PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));
1361: /* filter overlapped local cells */
1362: PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
1363: PetscCall(ISGetIndices(gid, &idxs));
1364: PetscCall(ISGetLocalSize(gid, &cum));
1365: PetscCall(PetscMalloc1(cum, &idxs2));
1366: for (c = cStart, cum = 0; c < cEnd; c++) {
1367: if (idxs[c - cStart] < 0) continue;
1368: idxs2[cum++] = idxs[c - cStart];
1369: }
1370: PetscCall(ISRestoreIndices(gid, &idxs));
1371: PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
1372: PetscCall(ISDestroy(&gid));
1373: PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));
1375: /* support for node-aware cell locality */
1376: PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
1377: PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
1378: PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
1379: PetscCall(VecGetArray(cown, &array));
1380: for (c = 0; c < numVertices; c++) array[c] = nid;
1381: PetscCall(VecRestoreArray(cown, &array));
1382: PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
1383: PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1384: PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1385: PetscCall(ISDestroy(&acis));
1386: PetscCall(VecScatterDestroy(&sct));
1387: PetscCall(VecDestroy(&cown));
1389: /* compute edgeCut */
1390: for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
1391: PetscCall(PetscMalloc1(cum, &work));
1392: PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
1393: PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
1394: PetscCall(ISDestroy(&gid));
1395: PetscCall(VecGetArray(acown, &array));
1396: for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1397: PetscInt totl;
1399: totl = start[c + 1] - start[c];
1400: PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work));
1401: for (i = 0; i < totl; i++) {
1402: if (work[i] < 0) {
1403: ect += 1;
1404: ectn += (array[i + start[c]] != nid) ? 0 : 1;
1405: }
1406: }
1407: }
1408: PetscCall(PetscFree(work));
1409: PetscCall(VecRestoreArray(acown, &array));
1410: lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT;
1411: lm[1] = -numVertices;
1412: PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm));
1413: PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0]));
1414: lm[0] = ect; /* edgeCut */
1415: lm[1] = ectn; /* node-aware edgeCut */
1416: lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1417: PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm));
1418: PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2]));
1419: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1420: PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.));
1421: #else
1422: PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0));
1423: #endif
1424: PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
1425: PetscCall(PetscFree(start));
1426: PetscCall(PetscFree(adjacency));
1427: PetscCall(VecDestroy(&acown));
1428: } else {
1429: const char *name;
1430: PetscInt *sizes, *hybsizes, *ghostsizes;
1431: PetscInt locDepth, depth, cellHeight, dim, d;
1432: PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum;
1433: PetscInt numLabels, l, maxSize = 17;
1434: DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1435: MPI_Comm comm;
1436: PetscMPIInt size, rank;
1438: PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1439: PetscCallMPI(MPI_Comm_size(comm, &size));
1440: PetscCallMPI(MPI_Comm_rank(comm, &rank));
1441: PetscCall(DMGetDimension(dm, &dim));
1442: PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1443: PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1444: if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
1445: else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
1446: if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight));
1447: PetscCall(DMPlexGetDepth(dm, &locDepth));
1448: PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
1449: PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd));
1450: gcNum = gcEnd - gcStart;
1451: if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
1452: else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1453: for (d = 0; d <= depth; d++) {
1454: PetscInt Nc[2] = {0, 0}, ict;
1456: PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
1457: if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1458: ict = ct0;
1459: PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1460: ct0 = (DMPolytopeType)ict;
1461: for (p = pStart; p < pEnd; ++p) {
1462: DMPolytopeType ct;
1464: PetscCall(DMPlexGetCellType(dm, p, &ct));
1465: if (ct == ct0) ++Nc[0];
1466: else ++Nc[1];
1467: }
1468: if (size < maxSize) {
1469: PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
1470: PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
1471: if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
1472: PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1473: for (p = 0; p < size; ++p) {
1474: if (rank == 0) {
1475: PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
1476: if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
1477: if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1478: }
1479: }
1480: } else {
1481: PetscInt locMinMax[2];
1483: locMinMax[0] = Nc[0] + Nc[1];
1484: locMinMax[1] = Nc[0] + Nc[1];
1485: PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
1486: locMinMax[0] = Nc[1];
1487: locMinMax[1] = Nc[1];
1488: PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1489: if (d == depth) {
1490: locMinMax[0] = gcNum;
1491: locMinMax[1] = gcNum;
1492: PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1493: }
1494: PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1495: PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
1496: if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
1497: if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1498: }
1499: PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1500: }
1501: PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
1502: {
1503: const PetscReal *maxCell;
1504: const PetscReal *L;
1505: PetscBool localized;
1507: PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
1508: PetscCall(DMGetCoordinatesLocalized(dm, &localized));
1509: if (L || localized) {
1510: PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
1511: PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1512: if (L) {
1513: PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
1514: for (d = 0; d < dim; ++d) {
1515: if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1516: PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
1517: }
1518: PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
1519: }
1520: PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
1521: PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1522: }
1523: }
1524: PetscCall(DMGetNumLabels(dm, &numLabels));
1525: if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1526: for (l = 0; l < numLabels; ++l) {
1527: DMLabel label;
1528: const char *name;
1529: IS valueIS;
1530: const PetscInt *values;
1531: PetscInt numValues, v;
1533: PetscCall(DMGetLabelName(dm, l, &name));
1534: PetscCall(DMGetLabel(dm, name, &label));
1535: PetscCall(DMLabelGetNumValues(label, &numValues));
1536: PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
1537: PetscCall(DMLabelGetValueIS(label, &valueIS));
1538: PetscCall(ISGetIndices(valueIS, &values));
1539: PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1540: for (v = 0; v < numValues; ++v) {
1541: PetscInt size;
1543: PetscCall(DMLabelGetStratumSize(label, values[v], &size));
1544: if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1545: PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1546: }
1547: PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
1548: PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1549: PetscCall(ISRestoreIndices(valueIS, &values));
1550: PetscCall(ISDestroy(&valueIS));
1551: }
1552: {
1553: char **labelNames;
1554: PetscInt Nl = numLabels;
1555: PetscBool flg;
1557: PetscCall(PetscMalloc1(Nl, &labelNames));
1558: PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1559: for (l = 0; l < Nl; ++l) {
1560: DMLabel label;
1562: PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1563: if (flg) {
1564: PetscCall(DMGetLabel(dm, labelNames[l], &label));
1565: PetscCall(DMLabelView(label, viewer));
1566: }
1567: PetscCall(PetscFree(labelNames[l]));
1568: }
1569: PetscCall(PetscFree(labelNames));
1570: }
1571: /* If no fields are specified, people do not want to see adjacency */
1572: if (dm->Nf) {
1573: PetscInt f;
1575: for (f = 0; f < dm->Nf; ++f) {
1576: const char *name;
1578: PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
1579: if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
1580: PetscCall(PetscViewerASCIIPushTab(viewer));
1581: if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
1582: if (dm->fields[f].adjacency[0]) {
1583: if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
1584: else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
1585: } else {
1586: if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
1587: else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
1588: }
1589: PetscCall(PetscViewerASCIIPopTab(viewer));
1590: }
1591: }
1592: PetscCall(DMGetCoarseDM(dm, &cdm));
1593: if (cdm) {
1594: PetscCall(PetscViewerASCIIPushTab(viewer));
1595: PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
1596: PetscCall(DMPlexView_Ascii(cdm, viewer));
1597: PetscCall(PetscViewerASCIIPopTab(viewer));
1598: }
1599: }
1600: PetscFunctionReturn(PETSC_SUCCESS);
1601: }
1603: static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1604: {
1605: DMPolytopeType ct;
1606: PetscMPIInt rank;
1607: PetscInt cdim;
1609: PetscFunctionBegin;
1610: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1611: PetscCall(DMPlexGetCellType(dm, cell, &ct));
1612: PetscCall(DMGetCoordinateDim(dm, &cdim));
1613: switch (ct) {
1614: case DM_POLYTOPE_SEGMENT:
1615: case DM_POLYTOPE_POINT_PRISM_TENSOR:
1616: switch (cdim) {
1617: case 1: {
1618: const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */
1619: const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1621: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK));
1622: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK));
1623: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK));
1624: } break;
1625: case 2: {
1626: const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1627: const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1628: const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy);
1630: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1631: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK));
1632: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK));
1633: } break;
1634: default:
1635: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1636: }
1637: break;
1638: case DM_POLYTOPE_TRIANGLE:
1639: PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1640: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1641: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1642: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1643: break;
1644: case DM_POLYTOPE_QUADRILATERAL:
1645: PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1646: PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1647: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1648: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1649: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1650: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1651: break;
1652: case DM_POLYTOPE_SEG_PRISM_TENSOR:
1653: PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1654: PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1655: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1656: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1657: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1658: PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1659: break;
1660: case DM_POLYTOPE_FV_GHOST:
1661: break;
1662: default:
1663: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1664: }
1665: PetscFunctionReturn(PETSC_SUCCESS);
1666: }
1668: static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1669: {
1670: DMPolytopeType ct;
1671: PetscReal centroid[2] = {0., 0.};
1672: PetscMPIInt rank;
1673: PetscInt fillColor, v, e, d;
1675: PetscFunctionBegin;
1676: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1677: PetscCall(DMPlexGetCellType(dm, cell, &ct));
1678: fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1679: switch (ct) {
1680: case DM_POLYTOPE_TRIANGLE: {
1681: PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1683: for (v = 0; v < 3; ++v) {
1684: centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.;
1685: centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.;
1686: }
1687: for (e = 0; e < 3; ++e) {
1688: refCoords[0] = refVertices[e * 2 + 0];
1689: refCoords[1] = refVertices[e * 2 + 1];
1690: for (d = 1; d <= edgeDiv; ++d) {
1691: refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv;
1692: refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv;
1693: }
1694: PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1695: for (d = 0; d < edgeDiv; ++d) {
1696: PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor));
1697: PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK));
1698: }
1699: }
1700: } break;
1701: default:
1702: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1703: }
1704: PetscFunctionReturn(PETSC_SUCCESS);
1705: }
1707: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1708: {
1709: PetscDraw draw;
1710: DM cdm;
1711: PetscSection coordSection;
1712: Vec coordinates;
1713: PetscReal xyl[3], xyr[3];
1714: PetscReal *refCoords, *edgeCoords;
1715: PetscBool isnull, drawAffine = PETSC_TRUE;
1716: PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4;
1718: PetscFunctionBegin;
1719: PetscCall(DMGetCoordinateDim(dm, &dim));
1720: PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
1721: PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
1722: if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
1723: PetscCall(DMGetCoordinateDM(dm, &cdm));
1724: PetscCall(DMGetLocalSection(cdm, &coordSection));
1725: PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1726: PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1727: PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1729: PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1730: PetscCall(PetscDrawIsNull(draw, &isnull));
1731: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
1732: PetscCall(PetscDrawSetTitle(draw, "Mesh"));
1734: PetscCall(DMGetBoundingBox(dm, xyl, xyr));
1735: PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
1736: PetscCall(PetscDrawClear(draw));
1738: for (c = cStart; c < cEnd; ++c) {
1739: PetscScalar *coords = NULL;
1740: const PetscScalar *coords_arr;
1741: PetscInt numCoords;
1742: PetscBool isDG;
1744: PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1745: if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
1746: else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1747: PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1748: }
1749: if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
1750: PetscCall(PetscDrawFlush(draw));
1751: PetscCall(PetscDrawPause(draw));
1752: PetscCall(PetscDrawSave(draw));
1753: PetscFunctionReturn(PETSC_SUCCESS);
1754: }
1756: #if defined(PETSC_HAVE_EXODUSII)
1757: #include <exodusII.h>
1758: #include <petscviewerexodusii.h>
1759: #endif
1761: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1762: {
1763: PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns;
1764: char name[PETSC_MAX_PATH_LEN];
1766: PetscFunctionBegin;
1769: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1770: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
1771: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1772: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1773: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
1774: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
1775: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
1776: if (iascii) {
1777: PetscViewerFormat format;
1778: PetscCall(PetscViewerGetFormat(viewer, &format));
1779: if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
1780: else PetscCall(DMPlexView_Ascii(dm, viewer));
1781: } else if (ishdf5) {
1782: #if defined(PETSC_HAVE_HDF5)
1783: PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1784: #else
1785: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1786: #endif
1787: } else if (isvtk) {
1788: PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
1789: } else if (isdraw) {
1790: PetscCall(DMPlexView_Draw(dm, viewer));
1791: } else if (isglvis) {
1792: PetscCall(DMPlexView_GLVis(dm, viewer));
1793: #if defined(PETSC_HAVE_EXODUSII)
1794: } else if (isexodus) {
1795: /*
1796: exodusII requires that all sets be part of exactly one cell set.
1797: If the dm does not have a "Cell Sets" label defined, we create one
1798: with ID 1, containing all cells.
1799: Note that if the Cell Sets label is defined but does not cover all cells,
1800: we may still have a problem. This should probably be checked here or in the viewer;
1801: */
1802: PetscInt numCS;
1803: PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
1804: if (!numCS) {
1805: PetscInt cStart, cEnd, c;
1806: PetscCall(DMCreateLabel(dm, "Cell Sets"));
1807: PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1808: for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
1809: }
1810: PetscCall(DMView_PlexExodusII(dm, viewer));
1811: #endif
1812: #if defined(PETSC_HAVE_CGNS)
1813: } else if (iscgns) {
1814: PetscCall(DMView_PlexCGNS(dm, viewer));
1815: #endif
1816: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1817: /* Optionally view the partition */
1818: PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
1819: if (flg) {
1820: Vec ranks;
1821: PetscCall(DMPlexCreateRankField(dm, &ranks));
1822: PetscCall(VecView(ranks, viewer));
1823: PetscCall(VecDestroy(&ranks));
1824: }
1825: /* Optionally view a label */
1826: PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1827: if (flg) {
1828: DMLabel label;
1829: Vec val;
1831: PetscCall(DMGetLabel(dm, name, &label));
1832: PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1833: PetscCall(DMPlexCreateLabelField(dm, label, &val));
1834: PetscCall(VecView(val, viewer));
1835: PetscCall(VecDestroy(&val));
1836: }
1837: PetscFunctionReturn(PETSC_SUCCESS);
1838: }
1840: /*@
1841: DMPlexTopologyView - Saves a `DMPLEX` topology into a file
1843: Collective
1845: Input Parameters:
1846: + dm - The `DM` whose topology is to be saved
1847: - viewer - The `PetscViewer` to save it in
1849: Level: advanced
1851: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
1852: @*/
1853: PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
1854: {
1855: PetscBool ishdf5;
1857: PetscFunctionBegin;
1860: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1861: PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
1862: if (ishdf5) {
1863: #if defined(PETSC_HAVE_HDF5)
1864: PetscViewerFormat format;
1865: PetscCall(PetscViewerGetFormat(viewer, &format));
1866: if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1867: IS globalPointNumbering;
1869: PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
1870: PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
1871: PetscCall(ISDestroy(&globalPointNumbering));
1872: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1873: #else
1874: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1875: #endif
1876: }
1877: PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
1878: PetscFunctionReturn(PETSC_SUCCESS);
1879: }
1881: /*@
1882: DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file
1884: Collective
1886: Input Parameters:
1887: + dm - The `DM` whose coordinates are to be saved
1888: - viewer - The `PetscViewer` for saving
1890: Level: advanced
1892: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
1893: @*/
1894: PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
1895: {
1896: PetscBool ishdf5;
1898: PetscFunctionBegin;
1901: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1902: PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
1903: if (ishdf5) {
1904: #if defined(PETSC_HAVE_HDF5)
1905: PetscViewerFormat format;
1906: PetscCall(PetscViewerGetFormat(viewer, &format));
1907: if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1908: PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
1909: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1910: #else
1911: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1912: #endif
1913: }
1914: PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
1915: PetscFunctionReturn(PETSC_SUCCESS);
1916: }
1918: /*@
1919: DMPlexLabelsView - Saves `DMPLEX` labels into a file
1921: Collective
1923: Input Parameters:
1924: + dm - The `DM` whose labels are to be saved
1925: - viewer - The `PetscViewer` for saving
1927: Level: advanced
1929: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
1930: @*/
1931: PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1932: {
1933: PetscBool ishdf5;
1935: PetscFunctionBegin;
1938: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1939: PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
1940: if (ishdf5) {
1941: #if defined(PETSC_HAVE_HDF5)
1942: IS globalPointNumbering;
1943: PetscViewerFormat format;
1945: PetscCall(PetscViewerGetFormat(viewer, &format));
1946: if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1947: PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
1948: PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
1949: PetscCall(ISDestroy(&globalPointNumbering));
1950: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1951: #else
1952: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1953: #endif
1954: }
1955: PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
1956: PetscFunctionReturn(PETSC_SUCCESS);
1957: }
1959: /*@
1960: DMPlexSectionView - Saves a section associated with a `DMPLEX`
1962: Collective
1964: Input Parameters:
1965: + dm - The `DM` that contains the topology on which the section to be saved is defined
1966: . viewer - The `PetscViewer` for saving
1967: - sectiondm - The `DM` that contains the section to be saved
1969: Level: advanced
1971: Notes:
1972: This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points.
1974: In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
1976: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
1977: @*/
1978: PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1979: {
1980: PetscBool ishdf5;
1982: PetscFunctionBegin;
1986: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1987: PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
1988: if (ishdf5) {
1989: #if defined(PETSC_HAVE_HDF5)
1990: PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
1991: #else
1992: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1993: #endif
1994: }
1995: PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
1996: PetscFunctionReturn(PETSC_SUCCESS);
1997: }
1999: /*@
2000: DMPlexGlobalVectorView - Saves a global vector
2002: Collective
2004: Input Parameters:
2005: + dm - The `DM` that represents the topology
2006: . viewer - The `PetscViewer` to save data with
2007: . sectiondm - The `DM` that contains the global section on which vec is defined
2008: - vec - The global vector to be saved
2010: Level: advanced
2012: Notes:
2013: In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2015: Calling sequence:
2016: .vb
2017: DMCreate(PETSC_COMM_WORLD, &dm);
2018: DMSetType(dm, DMPLEX);
2019: PetscObjectSetName((PetscObject)dm, "topologydm_name");
2020: DMClone(dm, §iondm);
2021: PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2022: PetscSectionCreate(PETSC_COMM_WORLD, §ion);
2023: DMPlexGetChart(sectiondm, &pStart, &pEnd);
2024: PetscSectionSetChart(section, pStart, pEnd);
2025: PetscSectionSetUp(section);
2026: DMSetLocalSection(sectiondm, section);
2027: PetscSectionDestroy(§ion);
2028: DMGetGlobalVector(sectiondm, &vec);
2029: PetscObjectSetName((PetscObject)vec, "vec_name");
2030: DMPlexTopologyView(dm, viewer);
2031: DMPlexSectionView(dm, viewer, sectiondm);
2032: DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2033: DMRestoreGlobalVector(sectiondm, &vec);
2034: DMDestroy(§iondm);
2035: DMDestroy(&dm);
2036: .ve
2038: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2039: @*/
2040: PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2041: {
2042: PetscBool ishdf5;
2044: PetscFunctionBegin;
2049: /* Check consistency */
2050: {
2051: PetscSection section;
2052: PetscBool includesConstraints;
2053: PetscInt m, m1;
2055: PetscCall(VecGetLocalSize(vec, &m1));
2056: PetscCall(DMGetGlobalSection(sectiondm, §ion));
2057: PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2058: if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2059: else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2060: PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2061: }
2062: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2063: PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2064: if (ishdf5) {
2065: #if defined(PETSC_HAVE_HDF5)
2066: PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2067: #else
2068: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2069: #endif
2070: }
2071: PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2072: PetscFunctionReturn(PETSC_SUCCESS);
2073: }
2075: /*@
2076: DMPlexLocalVectorView - Saves a local vector
2078: Collective
2080: Input Parameters:
2081: + dm - The `DM` that represents the topology
2082: . viewer - The `PetscViewer` to save data with
2083: . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm`
2084: - vec - The local vector to be saved
2086: Level: advanced
2088: Note:
2089: In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2091: Calling sequence:
2092: .vb
2093: DMCreate(PETSC_COMM_WORLD, &dm);
2094: DMSetType(dm, DMPLEX);
2095: PetscObjectSetName((PetscObject)dm, "topologydm_name");
2096: DMClone(dm, §iondm);
2097: PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2098: PetscSectionCreate(PETSC_COMM_WORLD, §ion);
2099: DMPlexGetChart(sectiondm, &pStart, &pEnd);
2100: PetscSectionSetChart(section, pStart, pEnd);
2101: PetscSectionSetUp(section);
2102: DMSetLocalSection(sectiondm, section);
2103: DMGetLocalVector(sectiondm, &vec);
2104: PetscObjectSetName((PetscObject)vec, "vec_name");
2105: DMPlexTopologyView(dm, viewer);
2106: DMPlexSectionView(dm, viewer, sectiondm);
2107: DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2108: DMRestoreLocalVector(sectiondm, &vec);
2109: DMDestroy(§iondm);
2110: DMDestroy(&dm);
2111: .ve
2113: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2114: @*/
2115: PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2116: {
2117: PetscBool ishdf5;
2119: PetscFunctionBegin;
2124: /* Check consistency */
2125: {
2126: PetscSection section;
2127: PetscBool includesConstraints;
2128: PetscInt m, m1;
2130: PetscCall(VecGetLocalSize(vec, &m1));
2131: PetscCall(DMGetLocalSection(sectiondm, §ion));
2132: PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2133: if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2134: else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2135: PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2136: }
2137: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2138: PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2139: if (ishdf5) {
2140: #if defined(PETSC_HAVE_HDF5)
2141: PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2142: #else
2143: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2144: #endif
2145: }
2146: PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2147: PetscFunctionReturn(PETSC_SUCCESS);
2148: }
2150: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2151: {
2152: PetscBool ishdf5;
2154: PetscFunctionBegin;
2157: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2158: if (ishdf5) {
2159: #if defined(PETSC_HAVE_HDF5)
2160: PetscViewerFormat format;
2161: PetscCall(PetscViewerGetFormat(viewer, &format));
2162: if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
2163: PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2164: } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2165: PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
2166: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2167: PetscFunctionReturn(PETSC_SUCCESS);
2168: #else
2169: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2170: #endif
2171: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2172: }
2174: /*@
2175: DMPlexTopologyLoad - Loads a topology into a `DMPLEX`
2177: Collective
2179: Input Parameters:
2180: + dm - The `DM` into which the topology is loaded
2181: - viewer - The `PetscViewer` for the saved topology
2183: Output Parameter:
2184: . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded
2186: Level: advanced
2188: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2189: `PetscViewer`, `PetscSF`
2190: @*/
2191: PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2192: {
2193: PetscBool ishdf5;
2195: PetscFunctionBegin;
2198: if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
2199: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2200: PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2201: if (ishdf5) {
2202: #if defined(PETSC_HAVE_HDF5)
2203: PetscViewerFormat format;
2204: PetscCall(PetscViewerGetFormat(viewer, &format));
2205: if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2206: PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2207: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2208: #else
2209: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2210: #endif
2211: }
2212: PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2213: PetscFunctionReturn(PETSC_SUCCESS);
2214: }
2216: /*@
2217: DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`
2219: Collective
2221: Input Parameters:
2222: + dm - The `DM` into which the coordinates are loaded
2223: . viewer - The `PetscViewer` for the saved coordinates
2224: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer
2226: Level: advanced
2228: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2229: `PetscSF`, `PetscViewer`
2230: @*/
2231: PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2232: {
2233: PetscBool ishdf5;
2235: PetscFunctionBegin;
2239: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2240: PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2241: if (ishdf5) {
2242: #if defined(PETSC_HAVE_HDF5)
2243: PetscViewerFormat format;
2244: PetscCall(PetscViewerGetFormat(viewer, &format));
2245: if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2246: PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2247: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2248: #else
2249: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2250: #endif
2251: }
2252: PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2253: PetscFunctionReturn(PETSC_SUCCESS);
2254: }
2256: /*@
2257: DMPlexLabelsLoad - Loads labels into a `DMPLEX`
2259: Collective
2261: Input Parameters:
2262: + dm - The `DM` into which the labels are loaded
2263: . viewer - The `PetscViewer` for the saved labels
2264: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer
2266: Level: advanced
2268: Note:
2269: The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs.
2271: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2272: `PetscSF`, `PetscViewer`
2273: @*/
2274: PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2275: {
2276: PetscBool ishdf5;
2278: PetscFunctionBegin;
2282: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2283: PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2284: if (ishdf5) {
2285: #if defined(PETSC_HAVE_HDF5)
2286: PetscViewerFormat format;
2288: PetscCall(PetscViewerGetFormat(viewer, &format));
2289: if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2290: PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2291: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2292: #else
2293: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2294: #endif
2295: }
2296: PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2297: PetscFunctionReturn(PETSC_SUCCESS);
2298: }
2300: /*@
2301: DMPlexSectionLoad - Loads section into a `DMPLEX`
2303: Collective
2305: Input Parameters:
2306: + dm - The `DM` that represents the topology
2307: . viewer - The `PetscViewer` that represents the on-disk section (sectionA)
2308: . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated
2309: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer
2311: Output Parameters:
2312: + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed)
2313: - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed)
2315: Level: advanced
2317: Notes:
2318: This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points.
2320: In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2322: The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section.
2324: Example using 2 processes:
2325: .vb
2326: NX (number of points on dm): 4
2327: sectionA : the on-disk section
2328: vecA : a vector associated with sectionA
2329: sectionB : sectiondm's local section constructed in this function
2330: vecB (local) : a vector associated with sectiondm's local section
2331: vecB (global) : a vector associated with sectiondm's global section
2333: rank 0 rank 1
2334: vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2335: sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad()
2336: sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad()
2337: sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad()
2338: [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF
2339: sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF
2340: sectionB->atlasDof : 1 0 1 | 1 3
2341: sectionB->atlasOff (no perm) : 0 1 1 | 0 1
2342: vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2343: vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2344: .ve
2345: where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2347: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2348: @*/
2349: PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2350: {
2351: PetscBool ishdf5;
2353: PetscFunctionBegin;
2358: if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
2359: if (localDofSF) PetscAssertPointer(localDofSF, 6);
2360: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2361: PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2362: if (ishdf5) {
2363: #if defined(PETSC_HAVE_HDF5)
2364: PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2365: #else
2366: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2367: #endif
2368: }
2369: PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2370: PetscFunctionReturn(PETSC_SUCCESS);
2371: }
2373: /*@
2374: DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
2376: Collective
2378: Input Parameters:
2379: + dm - The `DM` that represents the topology
2380: . viewer - The `PetscViewer` that represents the on-disk vector data
2381: . sectiondm - The `DM` that contains the global section on which vec is defined
2382: . sf - The `PetscSF` that migrates the on-disk vector data into vec
2383: - vec - The global vector to set values of
2385: Level: advanced
2387: Notes:
2388: In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2390: Calling sequence:
2391: .vb
2392: DMCreate(PETSC_COMM_WORLD, &dm);
2393: DMSetType(dm, DMPLEX);
2394: PetscObjectSetName((PetscObject)dm, "topologydm_name");
2395: DMPlexTopologyLoad(dm, viewer, &sfX);
2396: DMClone(dm, §iondm);
2397: PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2398: DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2399: DMGetGlobalVector(sectiondm, &vec);
2400: PetscObjectSetName((PetscObject)vec, "vec_name");
2401: DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2402: DMRestoreGlobalVector(sectiondm, &vec);
2403: PetscSFDestroy(&gsf);
2404: PetscSFDestroy(&sfX);
2405: DMDestroy(§iondm);
2406: DMDestroy(&dm);
2407: .ve
2409: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2410: `PetscSF`, `PetscViewer`
2411: @*/
2412: PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2413: {
2414: PetscBool ishdf5;
2416: PetscFunctionBegin;
2422: /* Check consistency */
2423: {
2424: PetscSection section;
2425: PetscBool includesConstraints;
2426: PetscInt m, m1;
2428: PetscCall(VecGetLocalSize(vec, &m1));
2429: PetscCall(DMGetGlobalSection(sectiondm, §ion));
2430: PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2431: if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2432: else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2433: PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2434: }
2435: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2436: PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2437: if (ishdf5) {
2438: #if defined(PETSC_HAVE_HDF5)
2439: PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2440: #else
2441: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2442: #endif
2443: }
2444: PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2445: PetscFunctionReturn(PETSC_SUCCESS);
2446: }
2448: /*@
2449: DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
2451: Collective
2453: Input Parameters:
2454: + dm - The `DM` that represents the topology
2455: . viewer - The `PetscViewer` that represents the on-disk vector data
2456: . sectiondm - The `DM` that contains the local section on which vec is defined
2457: . sf - The `PetscSF` that migrates the on-disk vector data into vec
2458: - vec - The local vector to set values of
2460: Level: advanced
2462: Notes:
2463: In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
2465: Calling sequence:
2466: .vb
2467: DMCreate(PETSC_COMM_WORLD, &dm);
2468: DMSetType(dm, DMPLEX);
2469: PetscObjectSetName((PetscObject)dm, "topologydm_name");
2470: DMPlexTopologyLoad(dm, viewer, &sfX);
2471: DMClone(dm, §iondm);
2472: PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2473: DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2474: DMGetLocalVector(sectiondm, &vec);
2475: PetscObjectSetName((PetscObject)vec, "vec_name");
2476: DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2477: DMRestoreLocalVector(sectiondm, &vec);
2478: PetscSFDestroy(&lsf);
2479: PetscSFDestroy(&sfX);
2480: DMDestroy(§iondm);
2481: DMDestroy(&dm);
2482: .ve
2484: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2485: `PetscSF`, `PetscViewer`
2486: @*/
2487: PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2488: {
2489: PetscBool ishdf5;
2491: PetscFunctionBegin;
2497: /* Check consistency */
2498: {
2499: PetscSection section;
2500: PetscBool includesConstraints;
2501: PetscInt m, m1;
2503: PetscCall(VecGetLocalSize(vec, &m1));
2504: PetscCall(DMGetLocalSection(sectiondm, §ion));
2505: PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2506: if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2507: else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2508: PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2509: }
2510: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2511: PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2512: if (ishdf5) {
2513: #if defined(PETSC_HAVE_HDF5)
2514: PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2515: #else
2516: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2517: #endif
2518: }
2519: PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2520: PetscFunctionReturn(PETSC_SUCCESS);
2521: }
2523: PetscErrorCode DMDestroy_Plex(DM dm)
2524: {
2525: DM_Plex *mesh = (DM_Plex *)dm->data;
2527: PetscFunctionBegin;
2528: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
2529: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
2530: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
2531: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
2532: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL));
2533: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2534: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
2535: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
2536: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
2537: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
2538: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2539: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2540: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
2541: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL));
2542: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL));
2543: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
2544: if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
2545: PetscCall(PetscSectionDestroy(&mesh->coneSection));
2546: PetscCall(PetscFree(mesh->cones));
2547: PetscCall(PetscFree(mesh->coneOrientations));
2548: PetscCall(PetscSectionDestroy(&mesh->supportSection));
2549: PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
2550: PetscCall(PetscFree(mesh->supports));
2551: PetscCall(PetscFree(mesh->cellTypes));
2552: PetscCall(DMPlexTransformDestroy(&mesh->tr));
2553: PetscCall(PetscFree(mesh->tetgenOpts));
2554: PetscCall(PetscFree(mesh->triangleOpts));
2555: PetscCall(PetscFree(mesh->transformType));
2556: PetscCall(PetscFree(mesh->distributionName));
2557: PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
2558: PetscCall(DMLabelDestroy(&mesh->subpointMap));
2559: PetscCall(ISDestroy(&mesh->subpointIS));
2560: PetscCall(ISDestroy(&mesh->globalVertexNumbers));
2561: PetscCall(ISDestroy(&mesh->globalCellNumbers));
2562: PetscCall(PetscSFDestroy(&mesh->periodic.face_sf));
2563: PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
2564: PetscCall(ISDestroy(&mesh->periodic.periodic_points));
2565: PetscCall(PetscSectionDestroy(&mesh->anchorSection));
2566: PetscCall(ISDestroy(&mesh->anchorIS));
2567: PetscCall(PetscSectionDestroy(&mesh->parentSection));
2568: PetscCall(PetscFree(mesh->parents));
2569: PetscCall(PetscFree(mesh->childIDs));
2570: PetscCall(PetscSectionDestroy(&mesh->childSection));
2571: PetscCall(PetscFree(mesh->children));
2572: PetscCall(DMDestroy(&mesh->referenceTree));
2573: PetscCall(PetscGridHashDestroy(&mesh->lbox));
2574: PetscCall(PetscFree(mesh->neighbors));
2575: if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2576: /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
2577: PetscCall(PetscFree(mesh));
2578: PetscFunctionReturn(PETSC_SUCCESS);
2579: }
2581: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2582: {
2583: PetscSection sectionGlobal;
2584: PetscInt bs = -1, mbs;
2585: PetscInt localSize, localStart = 0;
2586: PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2587: MatType mtype;
2588: ISLocalToGlobalMapping ltog;
2590: PetscFunctionBegin;
2591: PetscCall(MatInitializePackage());
2592: mtype = dm->mattype;
2593: PetscCall(DMGetGlobalSection(dm, §ionGlobal));
2594: /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
2595: PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
2596: PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
2597: PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
2598: PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
2599: PetscCall(MatSetType(*J, mtype));
2600: PetscCall(MatSetFromOptions(*J));
2601: PetscCall(MatGetBlockSize(*J, &mbs));
2602: if (mbs > 1) bs = mbs;
2603: PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
2604: PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
2605: PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
2606: PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
2607: PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
2608: PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
2609: PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
2610: PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2611: if (!isShell) {
2612: PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2613: PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2614: PetscInt pStart, pEnd, p, dof, cdof, num_fields;
2616: PetscCall(DMGetLocalToGlobalMapping(dm, <og));
2618: PetscCall(PetscCalloc1(localSize, &pblocks));
2619: PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2620: PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
2621: for (p = pStart; p < pEnd; ++p) {
2622: switch (dm->blocking_type) {
2623: case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
2624: PetscInt bdof, offset;
2626: PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
2627: PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
2628: PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
2629: for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof;
2630: dof = dof < 0 ? -(dof + 1) : dof;
2631: bdof = cdof && (dof - cdof) ? 1 : dof;
2632: if (dof) {
2633: if (bs < 0) {
2634: bs = bdof;
2635: } else if (bs != bdof) {
2636: bs = 1;
2637: }
2638: }
2639: } break;
2640: case DM_BLOCKING_FIELD_NODE: {
2641: for (PetscInt field = 0; field < num_fields; field++) {
2642: PetscInt num_comp, bdof, offset;
2643: PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2644: PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2645: if (dof < 0) continue;
2646: PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2647: PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2648: PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp);
2649: PetscInt num_nodes = dof / num_comp;
2650: for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2651: // Handle possibly constant block size (unlikely)
2652: bdof = cdof && (dof - cdof) ? 1 : dof;
2653: if (dof) {
2654: if (bs < 0) {
2655: bs = bdof;
2656: } else if (bs != bdof) {
2657: bs = 1;
2658: }
2659: }
2660: }
2661: } break;
2662: }
2663: }
2664: /* Must have same blocksize on all procs (some might have no points) */
2665: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2666: bsLocal[1] = bs;
2667: PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
2668: if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2669: else bs = bsMinMax[0];
2670: bs = PetscMax(1, bs);
2671: PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
2672: if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
2673: PetscCall(MatSetBlockSize(*J, bs));
2674: PetscCall(MatSetUp(*J));
2675: } else {
2676: PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
2677: PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
2678: PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2679: }
2680: { // Consolidate blocks
2681: PetscInt nblocks = 0;
2682: for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
2683: if (pblocks[i] == 0) continue;
2684: pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
2685: for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]);
2686: }
2687: PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
2688: }
2689: PetscCall(PetscFree(pblocks));
2690: }
2691: PetscCall(MatSetDM(*J, dm));
2692: PetscFunctionReturn(PETSC_SUCCESS);
2693: }
2695: /*@
2696: DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2698: Not Collective
2700: Input Parameter:
2701: . dm - The `DMPLEX`
2703: Output Parameter:
2704: . subsection - The subdomain section
2706: Level: developer
2708: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
2709: @*/
2710: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2711: {
2712: DM_Plex *mesh = (DM_Plex *)dm->data;
2714: PetscFunctionBegin;
2716: if (!mesh->subdomainSection) {
2717: PetscSection section;
2718: PetscSF sf;
2720: PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
2721: PetscCall(DMGetLocalSection(dm, §ion));
2722: PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
2723: PetscCall(PetscSFDestroy(&sf));
2724: }
2725: *subsection = mesh->subdomainSection;
2726: PetscFunctionReturn(PETSC_SUCCESS);
2727: }
2729: /*@
2730: DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`)
2732: Not Collective
2734: Input Parameter:
2735: . dm - The `DMPLEX`
2737: Output Parameters:
2738: + pStart - The first mesh point
2739: - pEnd - The upper bound for mesh points
2741: Level: beginner
2743: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
2744: @*/
2745: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2746: {
2747: DM_Plex *mesh = (DM_Plex *)dm->data;
2749: PetscFunctionBegin;
2751: if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
2752: else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
2753: PetscFunctionReturn(PETSC_SUCCESS);
2754: }
2756: /*@
2757: DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`)
2759: Not Collective
2761: Input Parameters:
2762: + dm - The `DMPLEX`
2763: . pStart - The first mesh point
2764: - pEnd - The upper bound for mesh points
2766: Level: beginner
2768: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
2769: @*/
2770: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2771: {
2772: DM_Plex *mesh = (DM_Plex *)dm->data;
2774: PetscFunctionBegin;
2776: PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
2777: PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
2778: PetscCall(PetscFree(mesh->cellTypes));
2779: PetscFunctionReturn(PETSC_SUCCESS);
2780: }
2782: /*@
2783: DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2785: Not Collective
2787: Input Parameters:
2788: + dm - The `DMPLEX`
2789: - p - The point, which must lie in the chart set with `DMPlexSetChart()`
2791: Output Parameter:
2792: . size - The cone size for point `p`
2794: Level: beginner
2796: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
2797: @*/
2798: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2799: {
2800: DM_Plex *mesh = (DM_Plex *)dm->data;
2802: PetscFunctionBegin;
2804: PetscAssertPointer(size, 3);
2805: if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
2806: else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
2807: PetscFunctionReturn(PETSC_SUCCESS);
2808: }
2810: /*@
2811: DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2813: Not Collective
2815: Input Parameters:
2816: + dm - The `DMPLEX`
2817: . p - The point, which must lie in the chart set with `DMPlexSetChart()`
2818: - size - The cone size for point `p`
2820: Level: beginner
2822: Note:
2823: This should be called after `DMPlexSetChart()`.
2825: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2826: @*/
2827: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2828: {
2829: DM_Plex *mesh = (DM_Plex *)dm->data;
2831: PetscFunctionBegin;
2833: PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
2834: PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
2835: PetscFunctionReturn(PETSC_SUCCESS);
2836: }
2838: /*@C
2839: DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2841: Not Collective
2843: Input Parameters:
2844: + dm - The `DMPLEX`
2845: - p - The point, which must lie in the chart set with `DMPlexSetChart()`
2847: Output Parameter:
2848: . cone - An array of points which are on the in-edges for point `p`
2850: Level: beginner
2852: Fortran Notes:
2853: You must also call `DMPlexRestoreCone()` after you finish using the returned array.
2854: `DMPlexRestoreCone()` is not needed/available in C.
2856: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
2857: @*/
2858: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2859: {
2860: DM_Plex *mesh = (DM_Plex *)dm->data;
2861: PetscInt off;
2863: PetscFunctionBegin;
2865: PetscAssertPointer(cone, 3);
2866: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
2867: *cone = &mesh->cones[off];
2868: PetscFunctionReturn(PETSC_SUCCESS);
2869: }
2871: /*@C
2872: DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
2874: Not Collective
2876: Input Parameters:
2877: + dm - The `DMPLEX`
2878: - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
2880: Output Parameters:
2881: + pConesSection - `PetscSection` describing the layout of `pCones`
2882: - pCones - An array of points which are on the in-edges for the point set `p`
2884: Level: intermediate
2886: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
2887: @*/
2888: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
2889: {
2890: PetscSection cs, newcs;
2891: PetscInt *cones;
2892: PetscInt *newarr = NULL;
2893: PetscInt n;
2895: PetscFunctionBegin;
2896: PetscCall(DMPlexGetCones(dm, &cones));
2897: PetscCall(DMPlexGetConeSection(dm, &cs));
2898: PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
2899: if (pConesSection) *pConesSection = newcs;
2900: if (pCones) {
2901: PetscCall(PetscSectionGetStorageSize(newcs, &n));
2902: PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
2903: }
2904: PetscFunctionReturn(PETSC_SUCCESS);
2905: }
2907: /*@
2908: DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2910: Not Collective
2912: Input Parameters:
2913: + dm - The `DMPLEX`
2914: - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
2916: Output Parameter:
2917: . expandedPoints - An array of vertices recursively expanded from input points
2919: Level: advanced
2921: Notes:
2922: Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections.
2924: There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate.
2926: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
2927: `DMPlexGetDepth()`, `IS`
2928: @*/
2929: PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2930: {
2931: IS *expandedPointsAll;
2932: PetscInt depth;
2934: PetscFunctionBegin;
2937: PetscAssertPointer(expandedPoints, 3);
2938: PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2939: *expandedPoints = expandedPointsAll[0];
2940: PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
2941: PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2942: PetscFunctionReturn(PETSC_SUCCESS);
2943: }
2945: /*@
2946: DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones).
2948: Not Collective
2950: Input Parameters:
2951: + dm - The `DMPLEX`
2952: - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
2954: Output Parameters:
2955: + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
2956: . expandedPoints - (optional) An array of index sets with recursively expanded cones
2957: - sections - (optional) An array of sections which describe mappings from points to their cone points
2959: Level: advanced
2961: Notes:
2962: Like `DMPlexGetConeTuple()` but recursive.
2964: Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points.
2965: For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2967: Array section has size equal to `depth`. Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\:
2968: (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
2969: (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].
2971: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
2972: `DMPlexGetDepth()`, `PetscSection`, `IS`
2973: @*/
2974: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2975: {
2976: const PetscInt *arr0 = NULL, *cone = NULL;
2977: PetscInt *arr = NULL, *newarr = NULL;
2978: PetscInt d, depth_, i, n, newn, cn, co, start, end;
2979: IS *expandedPoints_;
2980: PetscSection *sections_;
2982: PetscFunctionBegin;
2985: if (depth) PetscAssertPointer(depth, 3);
2986: if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
2987: if (sections) PetscAssertPointer(sections, 5);
2988: PetscCall(ISGetLocalSize(points, &n));
2989: PetscCall(ISGetIndices(points, &arr0));
2990: PetscCall(DMPlexGetDepth(dm, &depth_));
2991: PetscCall(PetscCalloc1(depth_, &expandedPoints_));
2992: PetscCall(PetscCalloc1(depth_, §ions_));
2993: arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
2994: for (d = depth_ - 1; d >= 0; d--) {
2995: PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d]));
2996: PetscCall(PetscSectionSetChart(sections_[d], 0, n));
2997: for (i = 0; i < n; i++) {
2998: PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
2999: if (arr[i] >= start && arr[i] < end) {
3000: PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
3001: PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3002: } else {
3003: PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3004: }
3005: }
3006: PetscCall(PetscSectionSetUp(sections_[d]));
3007: PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
3008: PetscCall(PetscMalloc1(newn, &newarr));
3009: for (i = 0; i < n; i++) {
3010: PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
3011: PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3012: if (cn > 1) {
3013: PetscCall(DMPlexGetCone(dm, arr[i], &cone));
3014: PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt)));
3015: } else {
3016: newarr[co] = arr[i];
3017: }
3018: }
3019: PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3020: arr = newarr;
3021: n = newn;
3022: }
3023: PetscCall(ISRestoreIndices(points, &arr0));
3024: *depth = depth_;
3025: if (expandedPoints) *expandedPoints = expandedPoints_;
3026: else {
3027: for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
3028: PetscCall(PetscFree(expandedPoints_));
3029: }
3030: if (sections) *sections = sections_;
3031: else {
3032: for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d]));
3033: PetscCall(PetscFree(sections_));
3034: }
3035: PetscFunctionReturn(PETSC_SUCCESS);
3036: }
3038: /*@
3039: DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`
3041: Not Collective
3043: Input Parameters:
3044: + dm - The `DMPLEX`
3045: - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`
3047: Output Parameters:
3048: + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3049: . expandedPoints - (optional) An array of recursively expanded cones
3050: - sections - (optional) An array of sections which describe mappings from points to their cone points
3052: Level: advanced
3054: Note:
3055: See `DMPlexGetConeRecursive()`
3057: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3058: `DMPlexGetDepth()`, `IS`, `PetscSection`
3059: @*/
3060: PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3061: {
3062: PetscInt d, depth_;
3064: PetscFunctionBegin;
3065: PetscCall(DMPlexGetDepth(dm, &depth_));
3066: PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3067: if (depth) *depth = 0;
3068: if (expandedPoints) {
3069: for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
3070: PetscCall(PetscFree(*expandedPoints));
3071: }
3072: if (sections) {
3073: for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
3074: PetscCall(PetscFree(*sections));
3075: }
3076: PetscFunctionReturn(PETSC_SUCCESS);
3077: }
3079: /*@
3080: DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point
3082: Not Collective
3084: Input Parameters:
3085: + dm - The `DMPLEX`
3086: . p - The point, which must lie in the chart set with `DMPlexSetChart()`
3087: - cone - An array of points which are on the in-edges for point `p`
3089: Level: beginner
3091: Note:
3092: This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3094: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3095: @*/
3096: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3097: {
3098: DM_Plex *mesh = (DM_Plex *)dm->data;
3099: PetscInt dof, off, c;
3101: PetscFunctionBegin;
3103: PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3104: if (dof) PetscAssertPointer(cone, 3);
3105: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3106: if (PetscDefined(USE_DEBUG)) {
3107: PetscInt pStart, pEnd;
3108: PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3109: PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3110: for (c = 0; c < dof; ++c) {
3111: PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd);
3112: mesh->cones[off + c] = cone[c];
3113: }
3114: } else {
3115: for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3116: }
3117: PetscFunctionReturn(PETSC_SUCCESS);
3118: }
3120: /*@C
3121: DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
3123: Not Collective
3125: Input Parameters:
3126: + dm - The `DMPLEX`
3127: - p - The point, which must lie in the chart set with `DMPlexSetChart()`
3129: Output Parameter:
3130: . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an
3131: integer giving the prescription for cone traversal.
3133: Level: beginner
3135: Note:
3136: The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3137: the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3138: of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3139: with the identity.
3141: Fortran Notes:
3142: You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array.
3143: `DMPlexRestoreConeOrientation()` is not needed/available in C.
3145: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3146: @*/
3147: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3148: {
3149: DM_Plex *mesh = (DM_Plex *)dm->data;
3150: PetscInt off;
3152: PetscFunctionBegin;
3154: if (PetscDefined(USE_DEBUG)) {
3155: PetscInt dof;
3156: PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3157: if (dof) PetscAssertPointer(coneOrientation, 3);
3158: }
3159: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3161: *coneOrientation = &mesh->coneOrientations[off];
3162: PetscFunctionReturn(PETSC_SUCCESS);
3163: }
3165: /*@
3166: DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
3168: Not Collective
3170: Input Parameters:
3171: + dm - The `DMPLEX`
3172: . p - The point, which must lie in the chart set with `DMPlexSetChart()`
3173: - coneOrientation - An array of orientations
3175: Level: beginner
3177: Notes:
3178: This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.
3180: The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`.
3182: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3183: @*/
3184: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3185: {
3186: DM_Plex *mesh = (DM_Plex *)dm->data;
3187: PetscInt pStart, pEnd;
3188: PetscInt dof, off, c;
3190: PetscFunctionBegin;
3192: PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3193: if (dof) PetscAssertPointer(coneOrientation, 3);
3194: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3195: if (PetscDefined(USE_DEBUG)) {
3196: PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3197: PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3198: for (c = 0; c < dof; ++c) {
3199: PetscInt cdof, o = coneOrientation[c];
3201: PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
3202: PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof);
3203: mesh->coneOrientations[off + c] = o;
3204: }
3205: } else {
3206: for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3207: }
3208: PetscFunctionReturn(PETSC_SUCCESS);
3209: }
3211: /*@
3212: DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
3214: Not Collective
3216: Input Parameters:
3217: + dm - The `DMPLEX`
3218: . p - The point, which must lie in the chart set with `DMPlexSetChart()`
3219: . conePos - The local index in the cone where the point should be put
3220: - conePoint - The mesh point to insert
3222: Level: beginner
3224: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3225: @*/
3226: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3227: {
3228: DM_Plex *mesh = (DM_Plex *)dm->data;
3229: PetscInt pStart, pEnd;
3230: PetscInt dof, off;
3232: PetscFunctionBegin;
3234: if (PetscDefined(USE_DEBUG)) {
3235: PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3236: PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3237: PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd);
3238: PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3239: PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof);
3240: }
3241: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3242: mesh->cones[off + conePos] = conePoint;
3243: PetscFunctionReturn(PETSC_SUCCESS);
3244: }
3246: /*@
3247: DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
3249: Not Collective
3251: Input Parameters:
3252: + dm - The `DMPLEX`
3253: . p - The point, which must lie in the chart set with `DMPlexSetChart()`
3254: . conePos - The local index in the cone where the point should be put
3255: - coneOrientation - The point orientation to insert
3257: Level: beginner
3259: Note:
3260: The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.
3262: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3263: @*/
3264: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3265: {
3266: DM_Plex *mesh = (DM_Plex *)dm->data;
3267: PetscInt pStart, pEnd;
3268: PetscInt dof, off;
3270: PetscFunctionBegin;
3272: if (PetscDefined(USE_DEBUG)) {
3273: PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3274: PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3275: PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3276: PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof);
3277: }
3278: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3279: mesh->coneOrientations[off + conePos] = coneOrientation;
3280: PetscFunctionReturn(PETSC_SUCCESS);
3281: }
3283: /*@C
3284: DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG
3286: Not collective
3288: Input Parameters:
3289: + dm - The DMPlex
3290: - p - The point, which must lie in the chart set with DMPlexSetChart()
3292: Output Parameters:
3293: + cone - An array of points which are on the in-edges for point `p`
3294: - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3295: integer giving the prescription for cone traversal.
3297: Level: beginner
3299: Notes:
3300: The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3301: the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3302: of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3303: with the identity.
3305: Fortran Notes:
3306: You must also call `DMPlexRestoreCone()` after you finish using the returned array.
3307: `DMPlexRestoreCone()` is not needed/available in C.
3309: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3310: @*/
3311: PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3312: {
3313: DM_Plex *mesh = (DM_Plex *)dm->data;
3315: PetscFunctionBegin;
3317: if (mesh->tr) {
3318: PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
3319: } else {
3320: PetscInt off;
3321: if (PetscDefined(USE_DEBUG)) {
3322: PetscInt dof;
3323: PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3324: if (dof) {
3325: if (cone) PetscAssertPointer(cone, 3);
3326: if (ornt) PetscAssertPointer(ornt, 4);
3327: }
3328: }
3329: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3330: if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB
3331: if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL;
3332: }
3333: PetscFunctionReturn(PETSC_SUCCESS);
3334: }
3336: /*@C
3337: DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG
3339: Not Collective
3341: Input Parameters:
3342: + dm - The DMPlex
3343: . p - The point, which must lie in the chart set with `DMPlexSetChart()`
3344: . cone - An array of points which are on the in-edges for point p
3345: - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3346: integer giving the prescription for cone traversal.
3348: Level: beginner
3350: Notes:
3351: The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3352: the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3353: of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3354: with the identity.
3356: Fortran Notes:
3357: You must also call `DMPlexRestoreCone()` after you finish using the returned array.
3358: `DMPlexRestoreCone()` is not needed/available in C.
3360: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3361: @*/
3362: PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3363: {
3364: DM_Plex *mesh = (DM_Plex *)dm->data;
3366: PetscFunctionBegin;
3368: if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
3369: PetscFunctionReturn(PETSC_SUCCESS);
3370: }
3372: /*@
3373: DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3375: Not Collective
3377: Input Parameters:
3378: + dm - The `DMPLEX`
3379: - p - The point, which must lie in the chart set with `DMPlexSetChart()`
3381: Output Parameter:
3382: . size - The support size for point `p`
3384: Level: beginner
3386: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3387: @*/
3388: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3389: {
3390: DM_Plex *mesh = (DM_Plex *)dm->data;
3392: PetscFunctionBegin;
3394: PetscAssertPointer(size, 3);
3395: PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
3396: PetscFunctionReturn(PETSC_SUCCESS);
3397: }
3399: /*@
3400: DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3402: Not Collective
3404: Input Parameters:
3405: + dm - The `DMPLEX`
3406: . p - The point, which must lie in the chart set with `DMPlexSetChart()`
3407: - size - The support size for point `p`
3409: Level: beginner
3411: Note:
3412: This should be called after `DMPlexSetChart()`.
3414: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3415: @*/
3416: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3417: {
3418: DM_Plex *mesh = (DM_Plex *)dm->data;
3420: PetscFunctionBegin;
3422: PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
3423: PetscFunctionReturn(PETSC_SUCCESS);
3424: }
3426: /*@C
3427: DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3429: Not Collective
3431: Input Parameters:
3432: + dm - The `DMPLEX`
3433: - p - The point, which must lie in the chart set with `DMPlexSetChart()`
3435: Output Parameter:
3436: . support - An array of points which are on the out-edges for point `p`
3438: Level: beginner
3440: Fortran Notes:
3441: You must also call `DMPlexRestoreSupport()` after you finish using the returned array.
3442: `DMPlexRestoreSupport()` is not needed/available in C.
3444: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3445: @*/
3446: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3447: {
3448: DM_Plex *mesh = (DM_Plex *)dm->data;
3449: PetscInt off;
3451: PetscFunctionBegin;
3453: PetscAssertPointer(support, 3);
3454: PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3455: *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB
3456: PetscFunctionReturn(PETSC_SUCCESS);
3457: }
3459: /*@
3460: DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
3462: Not Collective
3464: Input Parameters:
3465: + dm - The `DMPLEX`
3466: . p - The point, which must lie in the chart set with `DMPlexSetChart()`
3467: - support - An array of points which are on the out-edges for point `p`
3469: Level: beginner
3471: Note:
3472: This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`.
3474: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3475: @*/
3476: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3477: {
3478: DM_Plex *mesh = (DM_Plex *)dm->data;
3479: PetscInt pStart, pEnd;
3480: PetscInt dof, off, c;
3482: PetscFunctionBegin;
3484: PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3485: PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3486: if (dof) PetscAssertPointer(support, 3);
3487: PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3488: PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3489: for (c = 0; c < dof; ++c) {
3490: PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd);
3491: mesh->supports[off + c] = support[c];
3492: }
3493: PetscFunctionReturn(PETSC_SUCCESS);
3494: }
3496: /*@
3497: DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
3499: Not Collective
3501: Input Parameters:
3502: + dm - The `DMPLEX`
3503: . p - The point, which must lie in the chart set with `DMPlexSetChart()`
3504: . supportPos - The local index in the cone where the point should be put
3505: - supportPoint - The mesh point to insert
3507: Level: beginner
3509: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3510: @*/
3511: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3512: {
3513: DM_Plex *mesh = (DM_Plex *)dm->data;
3514: PetscInt pStart, pEnd;
3515: PetscInt dof, off;
3517: PetscFunctionBegin;
3519: PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3520: PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3521: PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3522: PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3523: PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd);
3524: PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof);
3525: mesh->supports[off + supportPos] = supportPoint;
3526: PetscFunctionReturn(PETSC_SUCCESS);
3527: }
3529: /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3530: PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3531: {
3532: switch (ct) {
3533: case DM_POLYTOPE_SEGMENT:
3534: if (o == -1) return -2;
3535: break;
3536: case DM_POLYTOPE_TRIANGLE:
3537: if (o == -3) return -1;
3538: if (o == -2) return -3;
3539: if (o == -1) return -2;
3540: break;
3541: case DM_POLYTOPE_QUADRILATERAL:
3542: if (o == -4) return -2;
3543: if (o == -3) return -1;
3544: if (o == -2) return -4;
3545: if (o == -1) return -3;
3546: break;
3547: default:
3548: return o;
3549: }
3550: return o;
3551: }
3553: /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3554: PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3555: {
3556: switch (ct) {
3557: case DM_POLYTOPE_SEGMENT:
3558: if ((o == -2) || (o == 1)) return -1;
3559: if (o == -1) return 0;
3560: break;
3561: case DM_POLYTOPE_TRIANGLE:
3562: if (o == -3) return -2;
3563: if (o == -2) return -1;
3564: if (o == -1) return -3;
3565: break;
3566: case DM_POLYTOPE_QUADRILATERAL:
3567: if (o == -4) return -2;
3568: if (o == -3) return -1;
3569: if (o == -2) return -4;
3570: if (o == -1) return -3;
3571: break;
3572: default:
3573: return o;
3574: }
3575: return o;
3576: }
3578: /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3579: PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3580: {
3581: PetscInt pStart, pEnd, p;
3583: PetscFunctionBegin;
3584: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3585: for (p = pStart; p < pEnd; ++p) {
3586: const PetscInt *cone, *ornt;
3587: PetscInt coneSize, c;
3589: PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
3590: PetscCall(DMPlexGetCone(dm, p, &cone));
3591: PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3592: for (c = 0; c < coneSize; ++c) {
3593: DMPolytopeType ct;
3594: const PetscInt o = ornt[c];
3596: PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3597: switch (ct) {
3598: case DM_POLYTOPE_SEGMENT:
3599: if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3600: if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3601: break;
3602: case DM_POLYTOPE_TRIANGLE:
3603: if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3604: if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3605: if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3606: break;
3607: case DM_POLYTOPE_QUADRILATERAL:
3608: if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3609: if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3610: if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
3611: if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3612: break;
3613: default:
3614: break;
3615: }
3616: }
3617: }
3618: PetscFunctionReturn(PETSC_SUCCESS);
3619: }
3621: static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
3622: {
3623: DM_Plex *mesh = (DM_Plex *)dm->data;
3625: PetscFunctionBeginHot;
3626: if (PetscDefined(USE_DEBUG) || mesh->tr) {
3627: if (useCone) {
3628: PetscCall(DMPlexGetConeSize(dm, p, size));
3629: PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
3630: } else {
3631: PetscCall(DMPlexGetSupportSize(dm, p, size));
3632: PetscCall(DMPlexGetSupport(dm, p, arr));
3633: }
3634: } else {
3635: if (useCone) {
3636: const PetscSection s = mesh->coneSection;
3637: const PetscInt ps = p - s->pStart;
3638: const PetscInt off = s->atlasOff[ps];
3640: *size = s->atlasDof[ps];
3641: *arr = mesh->cones + off;
3642: *ornt = mesh->coneOrientations + off;
3643: } else {
3644: const PetscSection s = mesh->supportSection;
3645: const PetscInt ps = p - s->pStart;
3646: const PetscInt off = s->atlasOff[ps];
3648: *size = s->atlasDof[ps];
3649: *arr = mesh->supports + off;
3650: }
3651: }
3652: PetscFunctionReturn(PETSC_SUCCESS);
3653: }
3655: static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
3656: {
3657: DM_Plex *mesh = (DM_Plex *)dm->data;
3659: PetscFunctionBeginHot;
3660: if (PetscDefined(USE_DEBUG) || mesh->tr) {
3661: if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
3662: }
3663: PetscFunctionReturn(PETSC_SUCCESS);
3664: }
3666: static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3667: {
3668: DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
3669: PetscInt *closure;
3670: const PetscInt *tmp = NULL, *tmpO = NULL;
3671: PetscInt off = 0, tmpSize, t;
3673: PetscFunctionBeginHot;
3674: if (ornt) {
3675: PetscCall(DMPlexGetCellType(dm, p, &ct));
3676: if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3677: }
3678: if (*points) {
3679: closure = *points;
3680: } else {
3681: PetscInt maxConeSize, maxSupportSize;
3682: PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3683: PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
3684: }
3685: PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3686: if (ct == DM_POLYTOPE_UNKNOWN) {
3687: closure[off++] = p;
3688: closure[off++] = 0;
3689: for (t = 0; t < tmpSize; ++t) {
3690: closure[off++] = tmp[t];
3691: closure[off++] = tmpO ? tmpO[t] : 0;
3692: }
3693: } else {
3694: const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);
3696: /* We assume that cells with a valid type have faces with a valid type */
3697: closure[off++] = p;
3698: closure[off++] = ornt;
3699: for (t = 0; t < tmpSize; ++t) {
3700: DMPolytopeType ft;
3702: PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3703: closure[off++] = tmp[arr[t]];
3704: closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3705: }
3706: }
3707: PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3708: if (numPoints) *numPoints = tmpSize + 1;
3709: if (points) *points = closure;
3710: PetscFunctionReturn(PETSC_SUCCESS);
3711: }
3713: /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
3714: static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3715: {
3716: const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3717: const PetscInt *cone, *ornt;
3718: PetscInt *pts, *closure = NULL;
3719: DMPolytopeType ft;
3720: PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3721: PetscInt dim, coneSize, c, d, clSize, cl;
3723: PetscFunctionBeginHot;
3724: PetscCall(DMGetDimension(dm, &dim));
3725: PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3726: PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3727: coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
3728: supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
3729: maxSize = PetscMax(coneSeries, supportSeries);
3730: if (*points) {
3731: pts = *points;
3732: } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
3733: c = 0;
3734: pts[c++] = point;
3735: pts[c++] = o;
3736: PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
3737: PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
3738: for (cl = 0; cl < clSize * 2; cl += 2) {
3739: pts[c++] = closure[cl];
3740: pts[c++] = closure[cl + 1];
3741: }
3742: PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
3743: for (cl = 0; cl < clSize * 2; cl += 2) {
3744: pts[c++] = closure[cl];
3745: pts[c++] = closure[cl + 1];
3746: }
3747: PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3748: for (d = 2; d < coneSize; ++d) {
3749: PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
3750: pts[c++] = cone[arr[d * 2 + 0]];
3751: pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
3752: }
3753: PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3754: if (dim >= 3) {
3755: for (d = 2; d < coneSize; ++d) {
3756: const PetscInt fpoint = cone[arr[d * 2 + 0]];
3757: const PetscInt *fcone, *fornt;
3758: PetscInt fconeSize, fc, i;
3760: PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
3761: const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
3762: PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3763: for (fc = 0; fc < fconeSize; ++fc) {
3764: const PetscInt cp = fcone[farr[fc * 2 + 0]];
3765: const PetscInt co = farr[fc * 2 + 1];
3767: for (i = 0; i < c; i += 2)
3768: if (pts[i] == cp) break;
3769: if (i == c) {
3770: PetscCall(DMPlexGetCellType(dm, cp, &ft));
3771: pts[c++] = cp;
3772: pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
3773: }
3774: }
3775: PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3776: }
3777: }
3778: *numPoints = c / 2;
3779: *points = pts;
3780: PetscFunctionReturn(PETSC_SUCCESS);
3781: }
3783: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3784: {
3785: DMPolytopeType ct;
3786: PetscInt *closure, *fifo;
3787: PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0;
3788: PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries;
3789: PetscInt depth, maxSize;
3791: PetscFunctionBeginHot;
3792: PetscCall(DMPlexGetDepth(dm, &depth));
3793: if (depth == 1) {
3794: PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
3795: PetscFunctionReturn(PETSC_SUCCESS);
3796: }
3797: PetscCall(DMPlexGetCellType(dm, p, &ct));
3798: if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3799: if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
3800: PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
3801: PetscFunctionReturn(PETSC_SUCCESS);
3802: }
3803: PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3804: coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
3805: supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
3806: maxSize = PetscMax(coneSeries, supportSeries);
3807: PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
3808: if (*points) {
3809: closure = *points;
3810: } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
3811: closure[closureSize++] = p;
3812: closure[closureSize++] = ornt;
3813: fifo[fifoSize++] = p;
3814: fifo[fifoSize++] = ornt;
3815: fifo[fifoSize++] = ct;
3816: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3817: while (fifoSize - fifoStart) {
3818: const PetscInt q = fifo[fifoStart++];
3819: const PetscInt o = fifo[fifoStart++];
3820: const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++];
3821: const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o);
3822: const PetscInt *tmp, *tmpO = NULL;
3823: PetscInt tmpSize, t;
3825: if (PetscDefined(USE_DEBUG)) {
3826: PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2;
3827: PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q);
3828: }
3829: PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
3830: for (t = 0; t < tmpSize; ++t) {
3831: const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
3832: const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
3833: const PetscInt cp = tmp[ip];
3834: PetscCall(DMPlexGetCellType(dm, cp, &ct));
3835: const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3836: PetscInt c;
3838: /* Check for duplicate */
3839: for (c = 0; c < closureSize; c += 2) {
3840: if (closure[c] == cp) break;
3841: }
3842: if (c == closureSize) {
3843: closure[closureSize++] = cp;
3844: closure[closureSize++] = co;
3845: fifo[fifoSize++] = cp;
3846: fifo[fifoSize++] = co;
3847: fifo[fifoSize++] = ct;
3848: }
3849: }
3850: PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
3851: }
3852: PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
3853: if (numPoints) *numPoints = closureSize / 2;
3854: if (points) *points = closure;
3855: PetscFunctionReturn(PETSC_SUCCESS);
3856: }
3858: /*@C
3859: DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
3861: Not Collective
3863: Input Parameters:
3864: + dm - The `DMPLEX`
3865: . p - The mesh point
3866: - useCone - `PETSC_TRUE` for the closure, otherwise return the star
3868: Input/Output Parameter:
3869: . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
3870: if `NULL` on input, internal storage will be returned, otherwise the provided array is used
3872: Output Parameter:
3873: . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
3875: Level: beginner
3877: Note:
3878: If using internal storage (points is `NULL` on input), each call overwrites the last output.
3880: Fortran Notes:
3881: The `numPoints` argument is not present in the Fortran binding since it is internal to the array.
3883: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3884: @*/
3885: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3886: {
3887: PetscFunctionBeginHot;
3889: if (numPoints) PetscAssertPointer(numPoints, 4);
3890: if (points) PetscAssertPointer(points, 5);
3891: PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
3892: PetscFunctionReturn(PETSC_SUCCESS);
3893: }
3895: /*@C
3896: DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3898: Not Collective
3900: Input Parameters:
3901: + dm - The `DMPLEX`
3902: . p - The mesh point
3903: . useCone - `PETSC_TRUE` for the closure, otherwise return the star
3904: . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
3905: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3907: Level: beginner
3909: Note:
3910: If not using internal storage (points is not `NULL` on input), this call is unnecessary
3912: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3913: @*/
3914: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3915: {
3916: PetscFunctionBeginHot;
3918: if (numPoints) *numPoints = 0;
3919: PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
3920: PetscFunctionReturn(PETSC_SUCCESS);
3921: }
3923: /*@
3924: DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3926: Not Collective
3928: Input Parameter:
3929: . dm - The `DMPLEX`
3931: Output Parameters:
3932: + maxConeSize - The maximum number of in-edges
3933: - maxSupportSize - The maximum number of out-edges
3935: Level: beginner
3937: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3938: @*/
3939: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3940: {
3941: DM_Plex *mesh = (DM_Plex *)dm->data;
3943: PetscFunctionBegin;
3945: if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
3946: if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
3947: PetscFunctionReturn(PETSC_SUCCESS);
3948: }
3950: PetscErrorCode DMSetUp_Plex(DM dm)
3951: {
3952: DM_Plex *mesh = (DM_Plex *)dm->data;
3953: PetscInt size, maxSupportSize;
3955: PetscFunctionBegin;
3957: PetscCall(PetscSectionSetUp(mesh->coneSection));
3958: PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
3959: PetscCall(PetscMalloc1(size, &mesh->cones));
3960: PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
3961: PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
3962: if (maxSupportSize) {
3963: PetscCall(PetscSectionSetUp(mesh->supportSection));
3964: PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
3965: PetscCall(PetscMalloc1(size, &mesh->supports));
3966: }
3967: PetscFunctionReturn(PETSC_SUCCESS);
3968: }
3970: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3971: {
3972: PetscFunctionBegin;
3973: if (subdm) PetscCall(DMClone(dm, subdm));
3974: PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
3975: if (subdm) (*subdm)->useNatural = dm->useNatural;
3976: if (dm->useNatural && dm->sfMigration) {
3977: PetscSF sfNatural;
3979: (*subdm)->sfMigration = dm->sfMigration;
3980: PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
3981: PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
3982: (*subdm)->sfNatural = sfNatural;
3983: }
3984: PetscFunctionReturn(PETSC_SUCCESS);
3985: }
3987: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
3988: {
3989: PetscInt i = 0;
3991: PetscFunctionBegin;
3992: PetscCall(DMClone(dms[0], superdm));
3993: PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
3994: (*superdm)->useNatural = PETSC_FALSE;
3995: for (i = 0; i < len; i++) {
3996: if (dms[i]->useNatural && dms[i]->sfMigration) {
3997: PetscSF sfNatural;
3999: (*superdm)->sfMigration = dms[i]->sfMigration;
4000: PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4001: (*superdm)->useNatural = PETSC_TRUE;
4002: PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4003: (*superdm)->sfNatural = sfNatural;
4004: break;
4005: }
4006: }
4007: PetscFunctionReturn(PETSC_SUCCESS);
4008: }
4010: /*@
4011: DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
4013: Not Collective
4015: Input Parameter:
4016: . dm - The `DMPLEX`
4018: Level: beginner
4020: Note:
4021: This should be called after all calls to `DMPlexSetCone()`
4023: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4024: @*/
4025: PetscErrorCode DMPlexSymmetrize(DM dm)
4026: {
4027: DM_Plex *mesh = (DM_Plex *)dm->data;
4028: PetscInt *offsets;
4029: PetscInt supportSize;
4030: PetscInt pStart, pEnd, p;
4032: PetscFunctionBegin;
4034: PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
4035: PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4036: /* Calculate support sizes */
4037: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4038: for (p = pStart; p < pEnd; ++p) {
4039: PetscInt dof, off, c;
4041: PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4042: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4043: for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4044: }
4045: PetscCall(PetscSectionSetUp(mesh->supportSection));
4046: /* Calculate supports */
4047: PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
4048: PetscCall(PetscMalloc1(supportSize, &mesh->supports));
4049: PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4050: for (p = pStart; p < pEnd; ++p) {
4051: PetscInt dof, off, c;
4053: PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4054: PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4055: for (c = off; c < off + dof; ++c) {
4056: const PetscInt q = mesh->cones[c];
4057: PetscInt offS;
4059: PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS));
4061: mesh->supports[offS + offsets[q]] = p;
4062: ++offsets[q];
4063: }
4064: }
4065: PetscCall(PetscFree(offsets));
4066: PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
4067: PetscFunctionReturn(PETSC_SUCCESS);
4068: }
4070: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4071: {
4072: IS stratumIS;
4074: PetscFunctionBegin;
4075: if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
4076: if (PetscDefined(USE_DEBUG)) {
4077: PetscInt qStart, qEnd, numLevels, level;
4078: PetscBool overlap = PETSC_FALSE;
4079: PetscCall(DMLabelGetNumValues(label, &numLevels));
4080: for (level = 0; level < numLevels; level++) {
4081: PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4082: if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
4083: overlap = PETSC_TRUE;
4084: break;
4085: }
4086: }
4087: PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd);
4088: }
4089: PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
4090: PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
4091: PetscCall(ISDestroy(&stratumIS));
4092: PetscFunctionReturn(PETSC_SUCCESS);
4093: }
4095: /*@
4096: DMPlexStratify - Computes the strata for all points in the `DMPLEX`
4098: Collective
4100: Input Parameter:
4101: . dm - The `DMPLEX`
4103: Level: beginner
4105: Notes:
4106: The strata group all points of the same grade, and this function calculates the strata. This
4107: grade can be seen as the height (or depth) of the point in the DAG.
4109: The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
4110: can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram).
4111: Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4112: meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
4113: until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or
4114: manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed
4115: via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1.
4117: The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4118: if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4119: we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose
4120: to interpolate only that one (e0), so that
4121: .vb
4122: cone(c0) = {e0, v2}
4123: cone(e0) = {v0, v1}
4124: .ve
4125: If `DMPlexStratify()` is run on this mesh, it will give depths
4126: .vb
4127: depth 0 = {v0, v1, v2}
4128: depth 1 = {e0, c0}
4129: .ve
4130: where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
4132: `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()`
4134: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4135: @*/
4136: PetscErrorCode DMPlexStratify(DM dm)
4137: {
4138: DM_Plex *mesh = (DM_Plex *)dm->data;
4139: DMLabel label;
4140: PetscInt pStart, pEnd, p;
4141: PetscInt numRoots = 0, numLeaves = 0;
4143: PetscFunctionBegin;
4145: PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));
4147: /* Create depth label */
4148: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4149: PetscCall(DMCreateLabel(dm, "depth"));
4150: PetscCall(DMPlexGetDepthLabel(dm, &label));
4152: {
4153: /* Initialize roots and count leaves */
4154: PetscInt sMin = PETSC_MAX_INT;
4155: PetscInt sMax = PETSC_MIN_INT;
4156: PetscInt coneSize, supportSize;
4158: for (p = pStart; p < pEnd; ++p) {
4159: PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4160: PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4161: if (!coneSize && supportSize) {
4162: sMin = PetscMin(p, sMin);
4163: sMax = PetscMax(p, sMax);
4164: ++numRoots;
4165: } else if (!supportSize && coneSize) {
4166: ++numLeaves;
4167: } else if (!supportSize && !coneSize) {
4168: /* Isolated points */
4169: sMin = PetscMin(p, sMin);
4170: sMax = PetscMax(p, sMax);
4171: }
4172: }
4173: PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4174: }
4176: if (numRoots + numLeaves == (pEnd - pStart)) {
4177: PetscInt sMin = PETSC_MAX_INT;
4178: PetscInt sMax = PETSC_MIN_INT;
4179: PetscInt coneSize, supportSize;
4181: for (p = pStart; p < pEnd; ++p) {
4182: PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4183: PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4184: if (!supportSize && coneSize) {
4185: sMin = PetscMin(p, sMin);
4186: sMax = PetscMax(p, sMax);
4187: }
4188: }
4189: PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4190: } else {
4191: PetscInt level = 0;
4192: PetscInt qStart, qEnd, q;
4194: PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4195: while (qEnd > qStart) {
4196: PetscInt sMin = PETSC_MAX_INT;
4197: PetscInt sMax = PETSC_MIN_INT;
4199: for (q = qStart; q < qEnd; ++q) {
4200: const PetscInt *support;
4201: PetscInt supportSize, s;
4203: PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4204: PetscCall(DMPlexGetSupport(dm, q, &support));
4205: for (s = 0; s < supportSize; ++s) {
4206: sMin = PetscMin(support[s], sMin);
4207: sMax = PetscMax(support[s], sMax);
4208: }
4209: }
4210: PetscCall(DMLabelGetNumValues(label, &level));
4211: PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4212: PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4213: }
4214: }
4215: { /* just in case there is an empty process */
4216: PetscInt numValues, maxValues = 0, v;
4218: PetscCall(DMLabelGetNumValues(label, &numValues));
4219: PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
4220: for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4221: }
4222: PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
4223: PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
4224: PetscFunctionReturn(PETSC_SUCCESS);
4225: }
4227: PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4228: {
4229: DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4230: PetscInt dim, depth, pheight, coneSize;
4232: PetscFunctionBeginHot;
4233: PetscCall(DMGetDimension(dm, &dim));
4234: PetscCall(DMPlexGetDepth(dm, &depth));
4235: PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4236: pheight = depth - pdepth;
4237: if (depth <= 1) {
4238: switch (pdepth) {
4239: case 0:
4240: ct = DM_POLYTOPE_POINT;
4241: break;
4242: case 1:
4243: switch (coneSize) {
4244: case 2:
4245: ct = DM_POLYTOPE_SEGMENT;
4246: break;
4247: case 3:
4248: ct = DM_POLYTOPE_TRIANGLE;
4249: break;
4250: case 4:
4251: switch (dim) {
4252: case 2:
4253: ct = DM_POLYTOPE_QUADRILATERAL;
4254: break;
4255: case 3:
4256: ct = DM_POLYTOPE_TETRAHEDRON;
4257: break;
4258: default:
4259: break;
4260: }
4261: break;
4262: case 5:
4263: ct = DM_POLYTOPE_PYRAMID;
4264: break;
4265: case 6:
4266: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4267: break;
4268: case 8:
4269: ct = DM_POLYTOPE_HEXAHEDRON;
4270: break;
4271: default:
4272: break;
4273: }
4274: }
4275: } else {
4276: if (pdepth == 0) {
4277: ct = DM_POLYTOPE_POINT;
4278: } else if (pheight == 0) {
4279: switch (dim) {
4280: case 1:
4281: switch (coneSize) {
4282: case 2:
4283: ct = DM_POLYTOPE_SEGMENT;
4284: break;
4285: default:
4286: break;
4287: }
4288: break;
4289: case 2:
4290: switch (coneSize) {
4291: case 3:
4292: ct = DM_POLYTOPE_TRIANGLE;
4293: break;
4294: case 4:
4295: ct = DM_POLYTOPE_QUADRILATERAL;
4296: break;
4297: default:
4298: break;
4299: }
4300: break;
4301: case 3:
4302: switch (coneSize) {
4303: case 4:
4304: ct = DM_POLYTOPE_TETRAHEDRON;
4305: break;
4306: case 5: {
4307: const PetscInt *cone;
4308: PetscInt faceConeSize;
4310: PetscCall(DMPlexGetCone(dm, p, &cone));
4311: PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4312: switch (faceConeSize) {
4313: case 3:
4314: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4315: break;
4316: case 4:
4317: ct = DM_POLYTOPE_PYRAMID;
4318: break;
4319: }
4320: } break;
4321: case 6:
4322: ct = DM_POLYTOPE_HEXAHEDRON;
4323: break;
4324: default:
4325: break;
4326: }
4327: break;
4328: default:
4329: break;
4330: }
4331: } else if (pheight > 0) {
4332: switch (coneSize) {
4333: case 2:
4334: ct = DM_POLYTOPE_SEGMENT;
4335: break;
4336: case 3:
4337: ct = DM_POLYTOPE_TRIANGLE;
4338: break;
4339: case 4:
4340: ct = DM_POLYTOPE_QUADRILATERAL;
4341: break;
4342: default:
4343: break;
4344: }
4345: }
4346: }
4347: *pt = ct;
4348: PetscFunctionReturn(PETSC_SUCCESS);
4349: }
4351: /*@
4352: DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4354: Collective
4356: Input Parameter:
4357: . dm - The `DMPLEX`
4359: Level: developer
4361: Note:
4362: This function is normally called automatically when a cell type is requested. It creates an
4363: internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable
4364: automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype").
4366: `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()`
4368: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4369: @*/
4370: PetscErrorCode DMPlexComputeCellTypes(DM dm)
4371: {
4372: DM_Plex *mesh;
4373: DMLabel ctLabel;
4374: PetscInt pStart, pEnd, p;
4376: PetscFunctionBegin;
4378: mesh = (DM_Plex *)dm->data;
4379: PetscCall(DMCreateLabel(dm, "celltype"));
4380: PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
4381: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4382: PetscCall(PetscFree(mesh->cellTypes));
4383: PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4384: for (p = pStart; p < pEnd; ++p) {
4385: DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4386: PetscInt pdepth;
4388: PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
4389: PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4390: PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p);
4391: PetscCall(DMLabelSetValue(ctLabel, p, ct));
4392: mesh->cellTypes[p - pStart].value_as_uint8 = ct;
4393: }
4394: PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
4395: PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
4396: PetscFunctionReturn(PETSC_SUCCESS);
4397: }
4399: /*@C
4400: DMPlexGetJoin - Get an array for the join of the set of points
4402: Not Collective
4404: Input Parameters:
4405: + dm - The `DMPLEX` object
4406: . numPoints - The number of input points for the join
4407: - points - The input points
4409: Output Parameters:
4410: + numCoveredPoints - The number of points in the join
4411: - coveredPoints - The points in the join
4413: Level: intermediate
4415: Note:
4416: Currently, this is restricted to a single level join
4418: Fortran Notes:
4419: The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4421: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4422: @*/
4423: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4424: {
4425: DM_Plex *mesh = (DM_Plex *)dm->data;
4426: PetscInt *join[2];
4427: PetscInt joinSize, i = 0;
4428: PetscInt dof, off, p, c, m;
4429: PetscInt maxSupportSize;
4431: PetscFunctionBegin;
4433: PetscAssertPointer(points, 3);
4434: PetscAssertPointer(numCoveredPoints, 4);
4435: PetscAssertPointer(coveredPoints, 5);
4436: PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
4437: PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
4438: PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4439: /* Copy in support of first point */
4440: PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
4441: PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4442: for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4443: /* Check each successive support */
4444: for (p = 1; p < numPoints; ++p) {
4445: PetscInt newJoinSize = 0;
4447: PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
4448: PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4449: for (c = 0; c < dof; ++c) {
4450: const PetscInt point = mesh->supports[off + c];
4452: for (m = 0; m < joinSize; ++m) {
4453: if (point == join[i][m]) {
4454: join[1 - i][newJoinSize++] = point;
4455: break;
4456: }
4457: }
4458: }
4459: joinSize = newJoinSize;
4460: i = 1 - i;
4461: }
4462: *numCoveredPoints = joinSize;
4463: *coveredPoints = join[i];
4464: PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
4465: PetscFunctionReturn(PETSC_SUCCESS);
4466: }
4468: /*@C
4469: DMPlexRestoreJoin - Restore an array for the join of the set of points
4471: Not Collective
4473: Input Parameters:
4474: + dm - The `DMPLEX` object
4475: . numPoints - The number of input points for the join
4476: - points - The input points
4478: Output Parameters:
4479: + numCoveredPoints - The number of points in the join
4480: - coveredPoints - The points in the join
4482: Level: intermediate
4484: Fortran Notes:
4485: The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4487: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4488: @*/
4489: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4490: {
4491: PetscFunctionBegin;
4493: if (points) PetscAssertPointer(points, 3);
4494: if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
4495: PetscAssertPointer(coveredPoints, 5);
4496: PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4497: if (numCoveredPoints) *numCoveredPoints = 0;
4498: PetscFunctionReturn(PETSC_SUCCESS);
4499: }
4501: /*@C
4502: DMPlexGetFullJoin - Get an array for the join of the set of points
4504: Not Collective
4506: Input Parameters:
4507: + dm - The `DMPLEX` object
4508: . numPoints - The number of input points for the join
4509: - points - The input points
4511: Output Parameters:
4512: + numCoveredPoints - The number of points in the join
4513: - coveredPoints - The points in the join
4515: Level: intermediate
4517: Fortran Notes:
4518: The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4520: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4521: @*/
4522: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4523: {
4524: PetscInt *offsets, **closures;
4525: PetscInt *join[2];
4526: PetscInt depth = 0, maxSize, joinSize = 0, i = 0;
4527: PetscInt p, d, c, m, ms;
4529: PetscFunctionBegin;
4531: PetscAssertPointer(points, 3);
4532: PetscAssertPointer(numCoveredPoints, 4);
4533: PetscAssertPointer(coveredPoints, 5);
4535: PetscCall(DMPlexGetDepth(dm, &depth));
4536: PetscCall(PetscCalloc1(numPoints, &closures));
4537: PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
4538: PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
4539: maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
4540: PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
4541: PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));
4543: for (p = 0; p < numPoints; ++p) {
4544: PetscInt closureSize;
4546: PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]));
4548: offsets[p * (depth + 2) + 0] = 0;
4549: for (d = 0; d < depth + 1; ++d) {
4550: PetscInt pStart, pEnd, i;
4552: PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4553: for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4554: if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4555: offsets[p * (depth + 2) + d + 1] = i;
4556: break;
4557: }
4558: }
4559: if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4560: }
4561: PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize);
4562: }
4563: for (d = 0; d < depth + 1; ++d) {
4564: PetscInt dof;
4566: /* Copy in support of first point */
4567: dof = offsets[d + 1] - offsets[d];
4568: for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4569: /* Check each successive cone */
4570: for (p = 1; p < numPoints && joinSize; ++p) {
4571: PetscInt newJoinSize = 0;
4573: dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d];
4574: for (c = 0; c < dof; ++c) {
4575: const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2];
4577: for (m = 0; m < joinSize; ++m) {
4578: if (point == join[i][m]) {
4579: join[1 - i][newJoinSize++] = point;
4580: break;
4581: }
4582: }
4583: }
4584: joinSize = newJoinSize;
4585: i = 1 - i;
4586: }
4587: if (joinSize) break;
4588: }
4589: *numCoveredPoints = joinSize;
4590: *coveredPoints = join[i];
4591: for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
4592: PetscCall(PetscFree(closures));
4593: PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
4594: PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
4595: PetscFunctionReturn(PETSC_SUCCESS);
4596: }
4598: /*@C
4599: DMPlexGetMeet - Get an array for the meet of the set of points
4601: Not Collective
4603: Input Parameters:
4604: + dm - The `DMPLEX` object
4605: . numPoints - The number of input points for the meet
4606: - points - The input points
4608: Output Parameters:
4609: + numCoveringPoints - The number of points in the meet
4610: - coveringPoints - The points in the meet
4612: Level: intermediate
4614: Note:
4615: Currently, this is restricted to a single level meet
4617: Fortran Notes:
4618: The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4620: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4621: @*/
4622: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4623: {
4624: DM_Plex *mesh = (DM_Plex *)dm->data;
4625: PetscInt *meet[2];
4626: PetscInt meetSize, i = 0;
4627: PetscInt dof, off, p, c, m;
4628: PetscInt maxConeSize;
4630: PetscFunctionBegin;
4632: PetscAssertPointer(points, 3);
4633: PetscAssertPointer(numCoveringPoints, 4);
4634: PetscAssertPointer(coveringPoints, 5);
4635: PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
4636: PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
4637: PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4638: /* Copy in cone of first point */
4639: PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
4640: PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4641: for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
4642: /* Check each successive cone */
4643: for (p = 1; p < numPoints; ++p) {
4644: PetscInt newMeetSize = 0;
4646: PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
4647: PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4648: for (c = 0; c < dof; ++c) {
4649: const PetscInt point = mesh->cones[off + c];
4651: for (m = 0; m < meetSize; ++m) {
4652: if (point == meet[i][m]) {
4653: meet[1 - i][newMeetSize++] = point;
4654: break;
4655: }
4656: }
4657: }
4658: meetSize = newMeetSize;
4659: i = 1 - i;
4660: }
4661: *numCoveringPoints = meetSize;
4662: *coveringPoints = meet[i];
4663: PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
4664: PetscFunctionReturn(PETSC_SUCCESS);
4665: }
4667: /*@C
4668: DMPlexRestoreMeet - Restore an array for the meet of the set of points
4670: Not Collective
4672: Input Parameters:
4673: + dm - The `DMPLEX` object
4674: . numPoints - The number of input points for the meet
4675: - points - The input points
4677: Output Parameters:
4678: + numCoveredPoints - The number of points in the meet
4679: - coveredPoints - The points in the meet
4681: Level: intermediate
4683: Fortran Notes:
4684: The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4686: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4687: @*/
4688: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4689: {
4690: PetscFunctionBegin;
4692: if (points) PetscAssertPointer(points, 3);
4693: if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
4694: PetscAssertPointer(coveredPoints, 5);
4695: PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4696: if (numCoveredPoints) *numCoveredPoints = 0;
4697: PetscFunctionReturn(PETSC_SUCCESS);
4698: }
4700: /*@C
4701: DMPlexGetFullMeet - Get an array for the meet of the set of points
4703: Not Collective
4705: Input Parameters:
4706: + dm - The `DMPLEX` object
4707: . numPoints - The number of input points for the meet
4708: - points - The input points
4710: Output Parameters:
4711: + numCoveredPoints - The number of points in the meet
4712: - coveredPoints - The points in the meet
4714: Level: intermediate
4716: Fortran Notes:
4717: The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.
4719: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4720: @*/
4721: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4722: {
4723: PetscInt *offsets, **closures;
4724: PetscInt *meet[2];
4725: PetscInt height = 0, maxSize, meetSize = 0, i = 0;
4726: PetscInt p, h, c, m, mc;
4728: PetscFunctionBegin;
4730: PetscAssertPointer(points, 3);
4731: PetscAssertPointer(numCoveredPoints, 4);
4732: PetscAssertPointer(coveredPoints, 5);
4734: PetscCall(DMPlexGetDepth(dm, &height));
4735: PetscCall(PetscMalloc1(numPoints, &closures));
4736: PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
4737: PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
4738: maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
4739: PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
4740: PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));
4742: for (p = 0; p < numPoints; ++p) {
4743: PetscInt closureSize;
4745: PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]));
4747: offsets[p * (height + 2) + 0] = 0;
4748: for (h = 0; h < height + 1; ++h) {
4749: PetscInt pStart, pEnd, i;
4751: PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4752: for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
4753: if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4754: offsets[p * (height + 2) + h + 1] = i;
4755: break;
4756: }
4757: }
4758: if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
4759: }
4760: PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize);
4761: }
4762: for (h = 0; h < height + 1; ++h) {
4763: PetscInt dof;
4765: /* Copy in cone of first point */
4766: dof = offsets[h + 1] - offsets[h];
4767: for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
4768: /* Check each successive cone */
4769: for (p = 1; p < numPoints && meetSize; ++p) {
4770: PetscInt newMeetSize = 0;
4772: dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h];
4773: for (c = 0; c < dof; ++c) {
4774: const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2];
4776: for (m = 0; m < meetSize; ++m) {
4777: if (point == meet[i][m]) {
4778: meet[1 - i][newMeetSize++] = point;
4779: break;
4780: }
4781: }
4782: }
4783: meetSize = newMeetSize;
4784: i = 1 - i;
4785: }
4786: if (meetSize) break;
4787: }
4788: *numCoveredPoints = meetSize;
4789: *coveredPoints = meet[i];
4790: for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
4791: PetscCall(PetscFree(closures));
4792: PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
4793: PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
4794: PetscFunctionReturn(PETSC_SUCCESS);
4795: }
4797: /*@C
4798: DMPlexEqual - Determine if two `DM` have the same topology
4800: Not Collective
4802: Input Parameters:
4803: + dmA - A `DMPLEX` object
4804: - dmB - A `DMPLEX` object
4806: Output Parameter:
4807: . equal - `PETSC_TRUE` if the topologies are identical
4809: Level: intermediate
4811: Note:
4812: We are not solving graph isomorphism, so we do not permute.
4814: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
4815: @*/
4816: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
4817: {
4818: PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
4820: PetscFunctionBegin;
4823: PetscAssertPointer(equal, 3);
4825: *equal = PETSC_FALSE;
4826: PetscCall(DMPlexGetDepth(dmA, &depth));
4827: PetscCall(DMPlexGetDepth(dmB, &depthB));
4828: if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
4829: PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
4830: PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
4831: if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
4832: for (p = pStart; p < pEnd; ++p) {
4833: const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
4834: PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s;
4836: PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
4837: PetscCall(DMPlexGetCone(dmA, p, &cone));
4838: PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
4839: PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
4840: PetscCall(DMPlexGetCone(dmB, p, &coneB));
4841: PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
4842: if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
4843: for (c = 0; c < coneSize; ++c) {
4844: if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
4845: if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
4846: }
4847: PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
4848: PetscCall(DMPlexGetSupport(dmA, p, &support));
4849: PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
4850: PetscCall(DMPlexGetSupport(dmB, p, &supportB));
4851: if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
4852: for (s = 0; s < supportSize; ++s) {
4853: if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
4854: }
4855: }
4856: *equal = PETSC_TRUE;
4857: PetscFunctionReturn(PETSC_SUCCESS);
4858: }
4860: /*@C
4861: DMPlexGetNumFaceVertices - Returns the number of vertices on a face
4863: Not Collective
4865: Input Parameters:
4866: + dm - The `DMPLEX`
4867: . cellDim - The cell dimension
4868: - numCorners - The number of vertices on a cell
4870: Output Parameter:
4871: . numFaceVertices - The number of vertices on a face
4873: Level: developer
4875: Note:
4876: Of course this can only work for a restricted set of symmetric shapes
4878: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
4879: @*/
4880: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4881: {
4882: MPI_Comm comm;
4884: PetscFunctionBegin;
4885: PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4886: PetscAssertPointer(numFaceVertices, 4);
4887: switch (cellDim) {
4888: case 0:
4889: *numFaceVertices = 0;
4890: break;
4891: case 1:
4892: *numFaceVertices = 1;
4893: break;
4894: case 2:
4895: switch (numCorners) {
4896: case 3: /* triangle */
4897: *numFaceVertices = 2; /* Edge has 2 vertices */
4898: break;
4899: case 4: /* quadrilateral */
4900: *numFaceVertices = 2; /* Edge has 2 vertices */
4901: break;
4902: case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
4903: *numFaceVertices = 3; /* Edge has 3 vertices */
4904: break;
4905: case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
4906: *numFaceVertices = 3; /* Edge has 3 vertices */
4907: break;
4908: default:
4909: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4910: }
4911: break;
4912: case 3:
4913: switch (numCorners) {
4914: case 4: /* tetradehdron */
4915: *numFaceVertices = 3; /* Face has 3 vertices */
4916: break;
4917: case 6: /* tet cohesive cells */
4918: *numFaceVertices = 4; /* Face has 4 vertices */
4919: break;
4920: case 8: /* hexahedron */
4921: *numFaceVertices = 4; /* Face has 4 vertices */
4922: break;
4923: case 9: /* tet cohesive Lagrange cells */
4924: *numFaceVertices = 6; /* Face has 6 vertices */
4925: break;
4926: case 10: /* quadratic tetrahedron */
4927: *numFaceVertices = 6; /* Face has 6 vertices */
4928: break;
4929: case 12: /* hex cohesive Lagrange cells */
4930: *numFaceVertices = 6; /* Face has 6 vertices */
4931: break;
4932: case 18: /* quadratic tet cohesive Lagrange cells */
4933: *numFaceVertices = 6; /* Face has 6 vertices */
4934: break;
4935: case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
4936: *numFaceVertices = 9; /* Face has 9 vertices */
4937: break;
4938: default:
4939: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4940: }
4941: break;
4942: default:
4943: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
4944: }
4945: PetscFunctionReturn(PETSC_SUCCESS);
4946: }
4948: /*@
4949: DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point
4951: Not Collective
4953: Input Parameter:
4954: . dm - The `DMPLEX` object
4956: Output Parameter:
4957: . depthLabel - The `DMLabel` recording point depth
4959: Level: developer
4961: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
4962: @*/
4963: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4964: {
4965: PetscFunctionBegin;
4967: PetscAssertPointer(depthLabel, 2);
4968: *depthLabel = dm->depthLabel;
4969: PetscFunctionReturn(PETSC_SUCCESS);
4970: }
4972: /*@
4973: DMPlexGetDepth - Get the depth of the DAG representing this mesh
4975: Not Collective
4977: Input Parameter:
4978: . dm - The `DMPLEX` object
4980: Output Parameter:
4981: . depth - The number of strata (breadth first levels) in the DAG
4983: Level: developer
4985: Notes:
4986: This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`.
4988: The point depth is described more in detail in `DMPlexGetDepthStratum()`.
4990: An empty mesh gives -1.
4992: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
4993: @*/
4994: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4995: {
4996: DM_Plex *mesh = (DM_Plex *)dm->data;
4997: DMLabel label;
4998: PetscInt d = 0;
5000: PetscFunctionBegin;
5002: PetscAssertPointer(depth, 2);
5003: if (mesh->tr) {
5004: PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
5005: } else {
5006: PetscCall(DMPlexGetDepthLabel(dm, &label));
5007: if (label) PetscCall(DMLabelGetNumValues(label, &d));
5008: *depth = d - 1;
5009: }
5010: PetscFunctionReturn(PETSC_SUCCESS);
5011: }
5013: /*@
5014: DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth.
5016: Not Collective
5018: Input Parameters:
5019: + dm - The `DMPLEX` object
5020: - depth - The requested depth
5022: Output Parameters:
5023: + start - The first point at this `depth`
5024: - end - One beyond the last point at this `depth`
5026: Level: developer
5028: Notes:
5029: Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points,
5030: often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next
5031: higher dimension, e.g., "edges".
5033: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5034: @*/
5035: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
5036: {
5037: DM_Plex *mesh = (DM_Plex *)dm->data;
5038: DMLabel label;
5039: PetscInt pStart, pEnd;
5041: PetscFunctionBegin;
5043: if (start) {
5044: PetscAssertPointer(start, 3);
5045: *start = 0;
5046: }
5047: if (end) {
5048: PetscAssertPointer(end, 4);
5049: *end = 0;
5050: }
5051: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5052: if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5053: if (depth < 0) {
5054: if (start) *start = pStart;
5055: if (end) *end = pEnd;
5056: PetscFunctionReturn(PETSC_SUCCESS);
5057: }
5058: if (mesh->tr) {
5059: PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
5060: } else {
5061: PetscCall(DMPlexGetDepthLabel(dm, &label));
5062: PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5063: PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
5064: }
5065: PetscFunctionReturn(PETSC_SUCCESS);
5066: }
5068: /*@
5069: DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height.
5071: Not Collective
5073: Input Parameters:
5074: + dm - The `DMPLEX` object
5075: - height - The requested height
5077: Output Parameters:
5078: + start - The first point at this `height`
5079: - end - One beyond the last point at this `height`
5081: Level: developer
5083: Notes:
5084: Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension
5085: points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height
5086: stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
5088: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5089: @*/
5090: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
5091: {
5092: DMLabel label;
5093: PetscInt depth, pStart, pEnd;
5095: PetscFunctionBegin;
5097: if (start) {
5098: PetscAssertPointer(start, 3);
5099: *start = 0;
5100: }
5101: if (end) {
5102: PetscAssertPointer(end, 4);
5103: *end = 0;
5104: }
5105: PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5106: if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5107: if (height < 0) {
5108: if (start) *start = pStart;
5109: if (end) *end = pEnd;
5110: PetscFunctionReturn(PETSC_SUCCESS);
5111: }
5112: PetscCall(DMPlexGetDepthLabel(dm, &label));
5113: if (label) PetscCall(DMLabelGetNumValues(label, &depth));
5114: else PetscCall(DMGetDimension(dm, &depth));
5115: PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
5116: PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
5117: PetscFunctionReturn(PETSC_SUCCESS);
5118: }
5120: /*@
5121: DMPlexGetPointDepth - Get the `depth` of a given point
5123: Not Collective
5125: Input Parameters:
5126: + dm - The `DMPLEX` object
5127: - point - The point
5129: Output Parameter:
5130: . depth - The depth of the `point`
5132: Level: intermediate
5134: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5135: @*/
5136: PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5137: {
5138: PetscFunctionBegin;
5140: PetscAssertPointer(depth, 3);
5141: PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
5142: PetscFunctionReturn(PETSC_SUCCESS);
5143: }
5145: /*@
5146: DMPlexGetPointHeight - Get the `height` of a given point
5148: Not Collective
5150: Input Parameters:
5151: + dm - The `DMPLEX` object
5152: - point - The point
5154: Output Parameter:
5155: . height - The height of the `point`
5157: Level: intermediate
5159: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
5160: @*/
5161: PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5162: {
5163: PetscInt n, pDepth;
5165: PetscFunctionBegin;
5167: PetscAssertPointer(height, 3);
5168: PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
5169: PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
5170: *height = n - 1 - pDepth; /* DAG depth is n-1 */
5171: PetscFunctionReturn(PETSC_SUCCESS);
5172: }
5174: /*@
5175: DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell
5177: Not Collective
5179: Input Parameter:
5180: . dm - The `DMPLEX` object
5182: Output Parameter:
5183: . celltypeLabel - The `DMLabel` recording cell polytope type
5185: Level: developer
5187: Note:
5188: This function will trigger automatica computation of cell types. This can be disabled by calling
5189: `DMCreateLabel`(dm, "celltype") beforehand.
5191: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5192: @*/
5193: PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5194: {
5195: PetscFunctionBegin;
5197: PetscAssertPointer(celltypeLabel, 2);
5198: if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5199: *celltypeLabel = dm->celltypeLabel;
5200: PetscFunctionReturn(PETSC_SUCCESS);
5201: }
5203: /*@
5204: DMPlexGetCellType - Get the polytope type of a given cell
5206: Not Collective
5208: Input Parameters:
5209: + dm - The `DMPLEX` object
5210: - cell - The cell
5212: Output Parameter:
5213: . celltype - The polytope type of the cell
5215: Level: intermediate
5217: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5218: @*/
5219: PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5220: {
5221: DM_Plex *mesh = (DM_Plex *)dm->data;
5222: DMLabel label;
5223: PetscInt ct;
5225: PetscFunctionBegin;
5227: PetscAssertPointer(celltype, 3);
5228: if (mesh->tr) {
5229: PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
5230: } else {
5231: PetscInt pStart, pEnd;
5233: PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
5234: if (!mesh->cellTypes) { /* XXX remove? optimize? */
5235: PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
5236: PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5237: PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5238: for (PetscInt p = pStart; p < pEnd; p++) {
5239: PetscCall(DMLabelGetValue(label, p, &ct));
5240: mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct;
5241: }
5242: }
5243: *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
5244: if (PetscDefined(USE_DEBUG)) {
5245: PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5246: PetscCall(DMLabelGetValue(label, cell, &ct));
5247: PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5248: PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
5249: }
5250: }
5251: PetscFunctionReturn(PETSC_SUCCESS);
5252: }
5254: /*@
5255: DMPlexSetCellType - Set the polytope type of a given cell
5257: Not Collective
5259: Input Parameters:
5260: + dm - The `DMPLEX` object
5261: . cell - The cell
5262: - celltype - The polytope type of the cell
5264: Level: advanced
5266: Note:
5267: By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function
5268: is executed. This function will override the computed type. However, if automatic classification will not succeed
5269: and a user wants to manually specify all types, the classification must be disabled by calling
5270: DMCreateLabel(dm, "celltype") before getting or setting any cell types.
5272: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5273: @*/
5274: PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5275: {
5276: DM_Plex *mesh = (DM_Plex *)dm->data;
5277: DMLabel label;
5278: PetscInt pStart, pEnd;
5280: PetscFunctionBegin;
5282: PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
5283: PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5284: PetscCall(DMLabelSetValue(label, cell, celltype));
5285: if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5286: mesh->cellTypes[cell - pStart].value_as_uint8 = celltype;
5287: PetscFunctionReturn(PETSC_SUCCESS);
5288: }
5290: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5291: {
5292: PetscSection section, s;
5293: Mat m;
5294: PetscInt maxHeight;
5295: const char *prefix;
5297: PetscFunctionBegin;
5298: PetscCall(DMClone(dm, cdm));
5299: PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5300: PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5301: PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
5302: PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
5303: PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
5304: PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion));
5305: PetscCall(DMSetLocalSection(*cdm, section));
5306: PetscCall(PetscSectionDestroy(§ion));
5307: PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
5308: PetscCall(MatCreate(PETSC_COMM_SELF, &m));
5309: PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL));
5310: PetscCall(PetscSectionDestroy(&s));
5311: PetscCall(MatDestroy(&m));
5313: PetscCall(DMSetNumFields(*cdm, 1));
5314: PetscCall(DMCreateDS(*cdm));
5315: (*cdm)->cloneOpts = PETSC_TRUE;
5316: if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
5317: PetscFunctionReturn(PETSC_SUCCESS);
5318: }
5320: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5321: {
5322: Vec coordsLocal, cellCoordsLocal;
5323: DM coordsDM, cellCoordsDM;
5325: PetscFunctionBegin;
5326: *field = NULL;
5327: PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
5328: PetscCall(DMGetCoordinateDM(dm, &coordsDM));
5329: PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
5330: PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5331: if (coordsLocal && coordsDM) {
5332: if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
5333: else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5334: }
5335: PetscFunctionReturn(PETSC_SUCCESS);
5336: }
5338: /*@C
5339: DMPlexGetConeSection - Return a section which describes the layout of cone data
5341: Not Collective
5343: Input Parameter:
5344: . dm - The `DMPLEX` object
5346: Output Parameter:
5347: . section - The `PetscSection` object
5349: Level: developer
5351: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
5352: @*/
5353: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5354: {
5355: DM_Plex *mesh = (DM_Plex *)dm->data;
5357: PetscFunctionBegin;
5359: if (section) *section = mesh->coneSection;
5360: PetscFunctionReturn(PETSC_SUCCESS);
5361: }
5363: /*@C
5364: DMPlexGetSupportSection - Return a section which describes the layout of support data
5366: Not Collective
5368: Input Parameter:
5369: . dm - The `DMPLEX` object
5371: Output Parameter:
5372: . section - The `PetscSection` object
5374: Level: developer
5376: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
5377: @*/
5378: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5379: {
5380: DM_Plex *mesh = (DM_Plex *)dm->data;
5382: PetscFunctionBegin;
5384: if (section) *section = mesh->supportSection;
5385: PetscFunctionReturn(PETSC_SUCCESS);
5386: }
5388: /*@C
5389: DMPlexGetCones - Return cone data
5391: Not Collective
5393: Input Parameter:
5394: . dm - The `DMPLEX` object
5396: Output Parameter:
5397: . cones - The cone for each point
5399: Level: developer
5401: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
5402: @*/
5403: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5404: {
5405: DM_Plex *mesh = (DM_Plex *)dm->data;
5407: PetscFunctionBegin;
5409: if (cones) *cones = mesh->cones;
5410: PetscFunctionReturn(PETSC_SUCCESS);
5411: }
5413: /*@C
5414: DMPlexGetConeOrientations - Return cone orientation data
5416: Not Collective
5418: Input Parameter:
5419: . dm - The `DMPLEX` object
5421: Output Parameter:
5422: . coneOrientations - The array of cone orientations for all points
5424: Level: developer
5426: Notes:
5427: The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`.
5429: The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`.
5431: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
5432: @*/
5433: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5434: {
5435: DM_Plex *mesh = (DM_Plex *)dm->data;
5437: PetscFunctionBegin;
5439: if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5440: PetscFunctionReturn(PETSC_SUCCESS);
5441: }
5443: /******************************** FEM Support **********************************/
5445: PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5446: {
5447: PetscInt depth;
5449: PetscFunctionBegin;
5450: PetscCall(DMPlexGetDepth(plex, &depth));
5451: PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5452: if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5453: PetscFunctionReturn(PETSC_SUCCESS);
5454: }
5456: /*
5457: Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point
5458: representing a line in the section.
5459: */
5460: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k)
5461: {
5462: PetscFunctionBeginHot;
5463: PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5464: if (line < 0) {
5465: *k = 0;
5466: *Nc = 0;
5467: } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */
5468: *k = 1;
5469: } else { /* Assume the full interpolated mesh is in the chart; lines in particular */
5470: /* An order k SEM disc has k-1 dofs on an edge */
5471: PetscCall(PetscSectionGetFieldDof(section, line, field, k));
5472: *k = *k / *Nc + 1;
5473: }
5474: PetscFunctionReturn(PETSC_SUCCESS);
5475: }
5477: /*@
5479: DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5480: lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
5481: section provided (or the section of the `DM`).
5483: Input Parameters:
5484: + dm - The `DM`
5485: . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE`
5486: - section - The `PetscSection` to reorder, or `NULL` for the default section
5488: Example:
5489: A typical interpolated single-quad mesh might order points as
5490: .vb
5491: [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5493: v4 -- e6 -- v3
5494: | |
5495: e7 c0 e8
5496: | |
5497: v1 -- e5 -- v2
5498: .ve
5500: (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign
5501: dofs in the order of points, e.g.,
5502: .vb
5503: c0 -> [0,1,2,3]
5504: v1 -> [4]
5505: ...
5506: e5 -> [8, 9]
5507: .ve
5509: which corresponds to the dofs
5510: .vb
5511: 6 10 11 7
5512: 13 2 3 15
5513: 12 0 1 14
5514: 4 8 9 5
5515: .ve
5517: The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5518: .vb
5519: 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5520: .ve
5522: After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5523: .vb
5524: 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5525: .ve
5527: Level: developer
5529: Notes:
5530: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5531: degree of the basis.
5533: This is required to run with libCEED.
5535: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5536: @*/
5537: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5538: {
5539: DMLabel label;
5540: PetscInt dim, depth = -1, eStart = -1, Nf;
5541: PetscBool vertexchart;
5543: PetscFunctionBegin;
5544: PetscCall(DMGetDimension(dm, &dim));
5545: if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
5546: if (point < 0) {
5547: PetscInt sStart, sEnd;
5549: PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5550: point = sEnd - sStart ? sStart : point;
5551: }
5552: PetscCall(DMPlexGetDepthLabel(dm, &label));
5553: if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
5554: if (!section) PetscCall(DMGetLocalSection(dm, §ion));
5555: if (depth == 1) {
5556: eStart = point;
5557: } else if (depth == dim) {
5558: const PetscInt *cone;
5560: PetscCall(DMPlexGetCone(dm, point, &cone));
5561: if (dim == 2) eStart = cone[0];
5562: else if (dim == 3) {
5563: const PetscInt *cone2;
5564: PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5565: eStart = cone2[0];
5566: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim);
5567: } else PetscCheck(depth < 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim);
5568: { /* Determine whether the chart covers all points or just vertices. */
5569: PetscInt pStart, pEnd, cStart, cEnd;
5570: PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd));
5571: PetscCall(PetscSectionGetChart(section, &cStart, &cEnd));
5572: if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */
5573: else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */
5574: else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */
5575: }
5576: PetscCall(PetscSectionGetNumFields(section, &Nf));
5577: for (PetscInt d = 1; d <= dim; d++) {
5578: PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5579: PetscInt *perm;
5581: for (f = 0; f < Nf; ++f) {
5582: PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5583: size += PetscPowInt(k + 1, d) * Nc;
5584: }
5585: PetscCall(PetscMalloc1(size, &perm));
5586: for (f = 0; f < Nf; ++f) {
5587: switch (d) {
5588: case 1:
5589: PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5590: /*
5591: Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5592: We want [ vtx0; edge of length k-1; vtx1 ]
5593: */
5594: for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
5595: for (i = 0; i < k - 1; i++)
5596: for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
5597: for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
5598: foffset = offset;
5599: break;
5600: case 2:
5601: /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
5602: PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5603: /* The SEM order is
5605: v_lb, {e_b}, v_rb,
5606: e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
5607: v_lt, reverse {e_t}, v_rt
5608: */
5609: {
5610: const PetscInt of = 0;
5611: const PetscInt oeb = of + PetscSqr(k - 1);
5612: const PetscInt oer = oeb + (k - 1);
5613: const PetscInt oet = oer + (k - 1);
5614: const PetscInt oel = oet + (k - 1);
5615: const PetscInt ovlb = oel + (k - 1);
5616: const PetscInt ovrb = ovlb + 1;
5617: const PetscInt ovrt = ovrb + 1;
5618: const PetscInt ovlt = ovrt + 1;
5619: PetscInt o;
5621: /* bottom */
5622: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
5623: for (o = oeb; o < oer; ++o)
5624: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5625: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
5626: /* middle */
5627: for (i = 0; i < k - 1; ++i) {
5628: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
5629: for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
5630: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5631: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
5632: }
5633: /* top */
5634: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
5635: for (o = oel - 1; o >= oet; --o)
5636: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5637: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
5638: foffset = offset;
5639: }
5640: break;
5641: case 3:
5642: /* The original hex closure is
5644: {c,
5645: f_b, f_t, f_f, f_b, f_r, f_l,
5646: e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb,
5647: v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
5648: */
5649: PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5650: /* The SEM order is
5651: Bottom Slice
5652: v_blf, {e^{(k-1)-n}_bf}, v_brf,
5653: e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
5654: v_blb, {e_bb}, v_brb,
5656: Middle Slice (j)
5657: {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
5658: f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
5659: e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
5661: Top Slice
5662: v_tlf, {e_tf}, v_trf,
5663: e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
5664: v_tlb, {e^{(k-1)-n}_tb}, v_trb,
5665: */
5666: {
5667: const PetscInt oc = 0;
5668: const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1);
5669: const PetscInt oft = ofb + PetscSqr(k - 1);
5670: const PetscInt off = oft + PetscSqr(k - 1);
5671: const PetscInt ofk = off + PetscSqr(k - 1);
5672: const PetscInt ofr = ofk + PetscSqr(k - 1);
5673: const PetscInt ofl = ofr + PetscSqr(k - 1);
5674: const PetscInt oebl = ofl + PetscSqr(k - 1);
5675: const PetscInt oebb = oebl + (k - 1);
5676: const PetscInt oebr = oebb + (k - 1);
5677: const PetscInt oebf = oebr + (k - 1);
5678: const PetscInt oetf = oebf + (k - 1);
5679: const PetscInt oetr = oetf + (k - 1);
5680: const PetscInt oetb = oetr + (k - 1);
5681: const PetscInt oetl = oetb + (k - 1);
5682: const PetscInt oerf = oetl + (k - 1);
5683: const PetscInt oelf = oerf + (k - 1);
5684: const PetscInt oelb = oelf + (k - 1);
5685: const PetscInt oerb = oelb + (k - 1);
5686: const PetscInt ovblf = oerb + (k - 1);
5687: const PetscInt ovblb = ovblf + 1;
5688: const PetscInt ovbrb = ovblb + 1;
5689: const PetscInt ovbrf = ovbrb + 1;
5690: const PetscInt ovtlf = ovbrf + 1;
5691: const PetscInt ovtrf = ovtlf + 1;
5692: const PetscInt ovtrb = ovtrf + 1;
5693: const PetscInt ovtlb = ovtrb + 1;
5694: PetscInt o, n;
5696: /* Bottom Slice */
5697: /* bottom */
5698: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
5699: for (o = oetf - 1; o >= oebf; --o)
5700: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5701: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
5702: /* middle */
5703: for (i = 0; i < k - 1; ++i) {
5704: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
5705: for (n = 0; n < k - 1; ++n) {
5706: o = ofb + n * (k - 1) + i;
5707: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5708: }
5709: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
5710: }
5711: /* top */
5712: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
5713: for (o = oebb; o < oebr; ++o)
5714: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5715: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;
5717: /* Middle Slice */
5718: for (j = 0; j < k - 1; ++j) {
5719: /* bottom */
5720: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
5721: for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
5722: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5723: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
5724: /* middle */
5725: for (i = 0; i < k - 1; ++i) {
5726: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
5727: for (n = 0; n < k - 1; ++n)
5728: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
5729: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
5730: }
5731: /* top */
5732: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
5733: for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
5734: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5735: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
5736: }
5738: /* Top Slice */
5739: /* bottom */
5740: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
5741: for (o = oetf; o < oetr; ++o)
5742: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5743: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
5744: /* middle */
5745: for (i = 0; i < k - 1; ++i) {
5746: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
5747: for (n = 0; n < k - 1; ++n)
5748: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
5749: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
5750: }
5751: /* top */
5752: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
5753: for (o = oetl - 1; o >= oetb; --o)
5754: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5755: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;
5757: foffset = offset;
5758: }
5759: break;
5760: default:
5761: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
5762: }
5763: }
5764: PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
5765: /* Check permutation */
5766: {
5767: PetscInt *check;
5769: PetscCall(PetscMalloc1(size, &check));
5770: for (i = 0; i < size; ++i) {
5771: check[i] = -1;
5772: PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]);
5773: }
5774: for (i = 0; i < size; ++i) check[perm[i]] = i;
5775: for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
5776: PetscCall(PetscFree(check));
5777: }
5778: PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
5779: if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
5780: PetscInt *loc_perm;
5781: PetscCall(PetscMalloc1(size * 2, &loc_perm));
5782: for (PetscInt i = 0; i < size; i++) {
5783: loc_perm[i] = perm[i];
5784: loc_perm[size + i] = size + perm[i];
5785: }
5786: PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
5787: }
5788: }
5789: PetscFunctionReturn(PETSC_SUCCESS);
5790: }
5792: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5793: {
5794: PetscDS prob;
5795: PetscInt depth, Nf, h;
5796: DMLabel label;
5798: PetscFunctionBeginHot;
5799: PetscCall(DMGetDS(dm, &prob));
5800: Nf = prob->Nf;
5801: label = dm->depthLabel;
5802: *dspace = NULL;
5803: if (field < Nf) {
5804: PetscObject disc = prob->disc[field];
5806: if (disc->classid == PETSCFE_CLASSID) {
5807: PetscDualSpace dsp;
5809: PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
5810: PetscCall(DMLabelGetNumValues(label, &depth));
5811: PetscCall(DMLabelGetValue(label, point, &h));
5812: h = depth - 1 - h;
5813: if (h) {
5814: PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
5815: } else {
5816: *dspace = dsp;
5817: }
5818: }
5819: }
5820: PetscFunctionReturn(PETSC_SUCCESS);
5821: }
5823: static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5824: {
5825: PetscScalar *array;
5826: const PetscScalar *vArray;
5827: const PetscInt *cone, *coneO;
5828: PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0;
5830: PetscFunctionBeginHot;
5831: PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
5832: PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
5833: PetscCall(DMPlexGetCone(dm, point, &cone));
5834: PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
5835: if (!values || !*values) {
5836: if ((point >= pStart) && (point < pEnd)) {
5837: PetscInt dof;
5839: PetscCall(PetscSectionGetDof(section, point, &dof));
5840: size += dof;
5841: }
5842: for (p = 0; p < numPoints; ++p) {
5843: const PetscInt cp = cone[p];
5844: PetscInt dof;
5846: if ((cp < pStart) || (cp >= pEnd)) continue;
5847: PetscCall(PetscSectionGetDof(section, cp, &dof));
5848: size += dof;
5849: }
5850: if (!values) {
5851: if (csize) *csize = size;
5852: PetscFunctionReturn(PETSC_SUCCESS);
5853: }
5854: PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
5855: } else {
5856: array = *values;
5857: }
5858: size = 0;
5859: PetscCall(VecGetArrayRead(v, &vArray));
5860: if ((point >= pStart) && (point < pEnd)) {
5861: PetscInt dof, off, d;
5862: const PetscScalar *varr;
5864: PetscCall(PetscSectionGetDof(section, point, &dof));
5865: PetscCall(PetscSectionGetOffset(section, point, &off));
5866: varr = &vArray[off];
5867: for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
5868: size += dof;
5869: }
5870: for (p = 0; p < numPoints; ++p) {
5871: const PetscInt cp = cone[p];
5872: PetscInt o = coneO[p];
5873: PetscInt dof, off, d;
5874: const PetscScalar *varr;
5876: if ((cp < pStart) || (cp >= pEnd)) continue;
5877: PetscCall(PetscSectionGetDof(section, cp, &dof));
5878: PetscCall(PetscSectionGetOffset(section, cp, &off));
5879: varr = &vArray[off];
5880: if (o >= 0) {
5881: for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
5882: } else {
5883: for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
5884: }
5885: size += dof;
5886: }
5887: PetscCall(VecRestoreArrayRead(v, &vArray));
5888: if (!*values) {
5889: if (csize) *csize = size;
5890: *values = array;
5891: } else {
5892: PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
5893: *csize = size;
5894: }
5895: PetscFunctionReturn(PETSC_SUCCESS);
5896: }
5898: /* Compress out points not in the section */
5899: static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5900: {
5901: const PetscInt np = *numPoints;
5902: PetscInt pStart, pEnd, p, q;
5904: PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
5905: for (p = 0, q = 0; p < np; ++p) {
5906: const PetscInt r = points[p * 2];
5907: if ((r >= pStart) && (r < pEnd)) {
5908: points[q * 2] = r;
5909: points[q * 2 + 1] = points[p * 2 + 1];
5910: ++q;
5911: }
5912: }
5913: *numPoints = q;
5914: return PETSC_SUCCESS;
5915: }
5917: /* Compressed closure does not apply closure permutation */
5918: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5919: {
5920: const PetscInt *cla = NULL;
5921: PetscInt np, *pts = NULL;
5923: PetscFunctionBeginHot;
5924: PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
5925: if (!ornt && *clPoints) {
5926: PetscInt dof, off;
5928: PetscCall(PetscSectionGetDof(*clSec, point, &dof));
5929: PetscCall(PetscSectionGetOffset(*clSec, point, &off));
5930: PetscCall(ISGetIndices(*clPoints, &cla));
5931: np = dof / 2;
5932: pts = (PetscInt *)&cla[off];
5933: } else {
5934: PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
5935: PetscCall(CompressPoints_Private(section, &np, pts));
5936: }
5937: *numPoints = np;
5938: *points = pts;
5939: *clp = cla;
5940: PetscFunctionReturn(PETSC_SUCCESS);
5941: }
5943: PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5944: {
5945: PetscFunctionBeginHot;
5946: if (!*clPoints) {
5947: PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
5948: } else {
5949: PetscCall(ISRestoreIndices(*clPoints, clp));
5950: }
5951: *numPoints = 0;
5952: *points = NULL;
5953: *clSec = NULL;
5954: *clPoints = NULL;
5955: *clp = NULL;
5956: PetscFunctionReturn(PETSC_SUCCESS);
5957: }
5959: static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5960: {
5961: PetscInt offset = 0, p;
5962: const PetscInt **perms = NULL;
5963: const PetscScalar **flips = NULL;
5965: PetscFunctionBeginHot;
5966: *size = 0;
5967: PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
5968: for (p = 0; p < numPoints; p++) {
5969: const PetscInt point = points[2 * p];
5970: const PetscInt *perm = perms ? perms[p] : NULL;
5971: const PetscScalar *flip = flips ? flips[p] : NULL;
5972: PetscInt dof, off, d;
5973: const PetscScalar *varr;
5975: PetscCall(PetscSectionGetDof(section, point, &dof));
5976: PetscCall(PetscSectionGetOffset(section, point, &off));
5977: varr = &vArray[off];
5978: if (clperm) {
5979: if (perm) {
5980: for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
5981: } else {
5982: for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
5983: }
5984: if (flip) {
5985: for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
5986: }
5987: } else {
5988: if (perm) {
5989: for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
5990: } else {
5991: for (d = 0; d < dof; d++) array[offset + d] = varr[d];
5992: }
5993: if (flip) {
5994: for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
5995: }
5996: }
5997: offset += dof;
5998: }
5999: PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
6000: *size = offset;
6001: PetscFunctionReturn(PETSC_SUCCESS);
6002: }
6004: static inline PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
6005: {
6006: PetscInt offset = 0, f;
6008: PetscFunctionBeginHot;
6009: *size = 0;
6010: for (f = 0; f < numFields; ++f) {
6011: PetscInt p;
6012: const PetscInt **perms = NULL;
6013: const PetscScalar **flips = NULL;
6015: PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6016: for (p = 0; p < numPoints; p++) {
6017: const PetscInt point = points[2 * p];
6018: PetscInt fdof, foff, b;
6019: const PetscScalar *varr;
6020: const PetscInt *perm = perms ? perms[p] : NULL;
6021: const PetscScalar *flip = flips ? flips[p] : NULL;
6023: PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6024: PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6025: varr = &vArray[foff];
6026: if (clperm) {
6027: if (perm) {
6028: for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
6029: } else {
6030: for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
6031: }
6032: if (flip) {
6033: for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
6034: }
6035: } else {
6036: if (perm) {
6037: for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
6038: } else {
6039: for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
6040: }
6041: if (flip) {
6042: for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
6043: }
6044: }
6045: offset += fdof;
6046: }
6047: PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6048: }
6049: *size = offset;
6050: PetscFunctionReturn(PETSC_SUCCESS);
6051: }
6053: PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
6054: {
6055: PetscSection clSection;
6056: IS clPoints;
6057: PetscInt *points = NULL;
6058: const PetscInt *clp, *perm = NULL;
6059: PetscInt depth, numFields, numPoints, asize;
6061: PetscFunctionBeginHot;
6063: if (!section) PetscCall(DMGetLocalSection(dm, §ion));
6066: PetscCall(DMPlexGetDepth(dm, &depth));
6067: PetscCall(PetscSectionGetNumFields(section, &numFields));
6068: if (depth == 1 && numFields < 2) {
6069: PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6070: PetscFunctionReturn(PETSC_SUCCESS);
6071: }
6072: /* Get points */
6073: PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
6074: /* Get sizes */
6075: asize = 0;
6076: for (PetscInt p = 0; p < numPoints * 2; p += 2) {
6077: PetscInt dof;
6078: PetscCall(PetscSectionGetDof(section, points[p], &dof));
6079: asize += dof;
6080: }
6081: if (values) {
6082: const PetscScalar *vArray;
6083: PetscInt size;
6085: if (*values) {
6086: PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize);
6087: } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6088: if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
6089: PetscCall(VecGetArrayRead(v, &vArray));
6090: /* Get values */
6091: if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
6092: else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
6093: PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
6094: /* Cleanup array */
6095: PetscCall(VecRestoreArrayRead(v, &vArray));
6096: }
6097: if (csize) *csize = asize;
6098: /* Cleanup points */
6099: PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6100: PetscFunctionReturn(PETSC_SUCCESS);
6101: }
6103: /*@C
6104: DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6106: Not collective
6108: Input Parameters:
6109: + dm - The `DM`
6110: . section - The section describing the layout in `v`, or `NULL` to use the default section
6111: . v - The local vector
6112: - point - The point in the `DM`
6114: Input/Output Parameters:
6115: + csize - The size of the input values array, or `NULL`; on output the number of values in the closure
6116: - values - An array to use for the values, or `NULL` to have it allocated automatically;
6117: if the user provided `NULL`, it is a borrowed array and should not be freed
6119: Level: intermediate
6121: Notes:
6122: `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6123: calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6124: assembly function, and a user may already have allocated storage for this operation.
6126: A typical use could be
6127: .vb
6128: values = NULL;
6129: PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6130: for (cl = 0; cl < clSize; ++cl) {
6131: <Compute on closure>
6132: }
6133: PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6134: .ve
6135: or
6136: .vb
6137: PetscMalloc1(clMaxSize, &values);
6138: for (p = pStart; p < pEnd; ++p) {
6139: clSize = clMaxSize;
6140: PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6141: for (cl = 0; cl < clSize; ++cl) {
6142: <Compute on closure>
6143: }
6144: }
6145: PetscFree(values);
6146: .ve
6148: Fortran Notes:
6149: The `csize` argument is not present in the Fortran binding since it is internal to the array.
6151: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6152: @*/
6153: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6154: {
6155: PetscFunctionBeginHot;
6156: PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values));
6157: PetscFunctionReturn(PETSC_SUCCESS);
6158: }
6160: PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6161: {
6162: DMLabel depthLabel;
6163: PetscSection clSection;
6164: IS clPoints;
6165: PetscScalar *array;
6166: const PetscScalar *vArray;
6167: PetscInt *points = NULL;
6168: const PetscInt *clp, *perm = NULL;
6169: PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size;
6171: PetscFunctionBeginHot;
6173: if (!section) PetscCall(DMGetLocalSection(dm, §ion));
6176: PetscCall(DMPlexGetDepth(dm, &mdepth));
6177: PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
6178: PetscCall(PetscSectionGetNumFields(section, &numFields));
6179: if (mdepth == 1 && numFields < 2) {
6180: PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6181: PetscFunctionReturn(PETSC_SUCCESS);
6182: }
6183: /* Get points */
6184: PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6185: for (clsize = 0, p = 0; p < Np; p++) {
6186: PetscInt dof;
6187: PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6188: clsize += dof;
6189: }
6190: PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6191: /* Filter points */
6192: for (p = 0; p < numPoints * 2; p += 2) {
6193: PetscInt dep;
6195: PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6196: if (dep != depth) continue;
6197: points[Np * 2 + 0] = points[p];
6198: points[Np * 2 + 1] = points[p + 1];
6199: ++Np;
6200: }
6201: /* Get array */
6202: if (!values || !*values) {
6203: PetscInt asize = 0, dof;
6205: for (p = 0; p < Np * 2; p += 2) {
6206: PetscCall(PetscSectionGetDof(section, points[p], &dof));
6207: asize += dof;
6208: }
6209: if (!values) {
6210: PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6211: if (csize) *csize = asize;
6212: PetscFunctionReturn(PETSC_SUCCESS);
6213: }
6214: PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6215: } else {
6216: array = *values;
6217: }
6218: PetscCall(VecGetArrayRead(v, &vArray));
6219: /* Get values */
6220: if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
6221: else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6222: /* Cleanup points */
6223: PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6224: /* Cleanup array */
6225: PetscCall(VecRestoreArrayRead(v, &vArray));
6226: if (!*values) {
6227: if (csize) *csize = size;
6228: *values = array;
6229: } else {
6230: PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6231: *csize = size;
6232: }
6233: PetscFunctionReturn(PETSC_SUCCESS);
6234: }
6236: /*@C
6237: DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6239: Not collective
6241: Input Parameters:
6242: + dm - The `DM`
6243: . section - The section describing the layout in `v`, or `NULL` to use the default section
6244: . v - The local vector
6245: . point - The point in the `DM`
6246: . csize - The number of values in the closure, or `NULL`
6247: - values - The array of values, which is a borrowed array and should not be freed
6249: Level: intermediate
6251: Note:
6252: The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()`
6254: Fortran Notes:
6255: The `csize` argument is not present in the Fortran binding since it is internal to the array.
6257: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6258: @*/
6259: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6260: {
6261: PetscInt size = 0;
6263: PetscFunctionBegin;
6264: /* Should work without recalculating size */
6265: PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6266: *values = NULL;
6267: PetscFunctionReturn(PETSC_SUCCESS);
6268: }
6270: static inline void add(PetscScalar *x, PetscScalar y)
6271: {
6272: *x += y;
6273: }
6274: static inline void insert(PetscScalar *x, PetscScalar y)
6275: {
6276: *x = y;
6277: }
6279: static inline PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
6280: {
6281: PetscInt cdof; /* The number of constraints on this point */
6282: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6283: PetscScalar *a;
6284: PetscInt off, cind = 0, k;
6286: PetscFunctionBegin;
6287: PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6288: PetscCall(PetscSectionGetOffset(section, point, &off));
6289: a = &array[off];
6290: if (!cdof || setBC) {
6291: if (clperm) {
6292: if (perm) {
6293: for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6294: } else {
6295: for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6296: }
6297: } else {
6298: if (perm) {
6299: for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6300: } else {
6301: for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6302: }
6303: }
6304: } else {
6305: PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6306: if (clperm) {
6307: if (perm) {
6308: for (k = 0; k < dof; ++k) {
6309: if ((cind < cdof) && (k == cdofs[cind])) {
6310: ++cind;
6311: continue;
6312: }
6313: fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6314: }
6315: } else {
6316: for (k = 0; k < dof; ++k) {
6317: if ((cind < cdof) && (k == cdofs[cind])) {
6318: ++cind;
6319: continue;
6320: }
6321: fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6322: }
6323: }
6324: } else {
6325: if (perm) {
6326: for (k = 0; k < dof; ++k) {
6327: if ((cind < cdof) && (k == cdofs[cind])) {
6328: ++cind;
6329: continue;
6330: }
6331: fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6332: }
6333: } else {
6334: for (k = 0; k < dof; ++k) {
6335: if ((cind < cdof) && (k == cdofs[cind])) {
6336: ++cind;
6337: continue;
6338: }
6339: fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6340: }
6341: }
6342: }
6343: }
6344: PetscFunctionReturn(PETSC_SUCCESS);
6345: }
6347: static inline PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
6348: {
6349: PetscInt cdof; /* The number of constraints on this point */
6350: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6351: PetscScalar *a;
6352: PetscInt off, cind = 0, k;
6354: PetscFunctionBegin;
6355: PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6356: PetscCall(PetscSectionGetOffset(section, point, &off));
6357: a = &array[off];
6358: if (cdof) {
6359: PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6360: if (clperm) {
6361: if (perm) {
6362: for (k = 0; k < dof; ++k) {
6363: if ((cind < cdof) && (k == cdofs[cind])) {
6364: fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6365: cind++;
6366: }
6367: }
6368: } else {
6369: for (k = 0; k < dof; ++k) {
6370: if ((cind < cdof) && (k == cdofs[cind])) {
6371: fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6372: cind++;
6373: }
6374: }
6375: }
6376: } else {
6377: if (perm) {
6378: for (k = 0; k < dof; ++k) {
6379: if ((cind < cdof) && (k == cdofs[cind])) {
6380: fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6381: cind++;
6382: }
6383: }
6384: } else {
6385: for (k = 0; k < dof; ++k) {
6386: if ((cind < cdof) && (k == cdofs[cind])) {
6387: fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6388: cind++;
6389: }
6390: }
6391: }
6392: }
6393: }
6394: PetscFunctionReturn(PETSC_SUCCESS);
6395: }
6397: static inline PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
6398: {
6399: PetscScalar *a;
6400: PetscInt fdof, foff, fcdof, foffset = *offset;
6401: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6402: PetscInt cind = 0, b;
6404: PetscFunctionBegin;
6405: PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6406: PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6407: PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6408: a = &array[foff];
6409: if (!fcdof || setBC) {
6410: if (clperm) {
6411: if (perm) {
6412: for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6413: } else {
6414: for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6415: }
6416: } else {
6417: if (perm) {
6418: for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6419: } else {
6420: for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6421: }
6422: }
6423: } else {
6424: PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6425: if (clperm) {
6426: if (perm) {
6427: for (b = 0; b < fdof; b++) {
6428: if ((cind < fcdof) && (b == fcdofs[cind])) {
6429: ++cind;
6430: continue;
6431: }
6432: fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6433: }
6434: } else {
6435: for (b = 0; b < fdof; b++) {
6436: if ((cind < fcdof) && (b == fcdofs[cind])) {
6437: ++cind;
6438: continue;
6439: }
6440: fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6441: }
6442: }
6443: } else {
6444: if (perm) {
6445: for (b = 0; b < fdof; b++) {
6446: if ((cind < fcdof) && (b == fcdofs[cind])) {
6447: ++cind;
6448: continue;
6449: }
6450: fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6451: }
6452: } else {
6453: for (b = 0; b < fdof; b++) {
6454: if ((cind < fcdof) && (b == fcdofs[cind])) {
6455: ++cind;
6456: continue;
6457: }
6458: fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6459: }
6460: }
6461: }
6462: }
6463: *offset += fdof;
6464: PetscFunctionReturn(PETSC_SUCCESS);
6465: }
6467: static inline PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar *, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
6468: {
6469: PetscScalar *a;
6470: PetscInt fdof, foff, fcdof, foffset = *offset;
6471: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6472: PetscInt Nc, cind = 0, ncind = 0, b;
6473: PetscBool ncSet, fcSet;
6475: PetscFunctionBegin;
6476: PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
6477: PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6478: PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6479: PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6480: a = &array[foff];
6481: if (fcdof) {
6482: /* We just override fcdof and fcdofs with Ncc and comps */
6483: PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6484: if (clperm) {
6485: if (perm) {
6486: if (comps) {
6487: for (b = 0; b < fdof; b++) {
6488: ncSet = fcSet = PETSC_FALSE;
6489: if (b % Nc == comps[ncind]) {
6490: ncind = (ncind + 1) % Ncc;
6491: ncSet = PETSC_TRUE;
6492: }
6493: if ((cind < fcdof) && (b == fcdofs[cind])) {
6494: ++cind;
6495: fcSet = PETSC_TRUE;
6496: }
6497: if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6498: }
6499: } else {
6500: for (b = 0; b < fdof; b++) {
6501: if ((cind < fcdof) && (b == fcdofs[cind])) {
6502: fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6503: ++cind;
6504: }
6505: }
6506: }
6507: } else {
6508: if (comps) {
6509: for (b = 0; b < fdof; b++) {
6510: ncSet = fcSet = PETSC_FALSE;
6511: if (b % Nc == comps[ncind]) {
6512: ncind = (ncind + 1) % Ncc;
6513: ncSet = PETSC_TRUE;
6514: }
6515: if ((cind < fcdof) && (b == fcdofs[cind])) {
6516: ++cind;
6517: fcSet = PETSC_TRUE;
6518: }
6519: if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6520: }
6521: } else {
6522: for (b = 0; b < fdof; b++) {
6523: if ((cind < fcdof) && (b == fcdofs[cind])) {
6524: fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6525: ++cind;
6526: }
6527: }
6528: }
6529: }
6530: } else {
6531: if (perm) {
6532: if (comps) {
6533: for (b = 0; b < fdof; b++) {
6534: ncSet = fcSet = PETSC_FALSE;
6535: if (b % Nc == comps[ncind]) {
6536: ncind = (ncind + 1) % Ncc;
6537: ncSet = PETSC_TRUE;
6538: }
6539: if ((cind < fcdof) && (b == fcdofs[cind])) {
6540: ++cind;
6541: fcSet = PETSC_TRUE;
6542: }
6543: if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6544: }
6545: } else {
6546: for (b = 0; b < fdof; b++) {
6547: if ((cind < fcdof) && (b == fcdofs[cind])) {
6548: fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6549: ++cind;
6550: }
6551: }
6552: }
6553: } else {
6554: if (comps) {
6555: for (b = 0; b < fdof; b++) {
6556: ncSet = fcSet = PETSC_FALSE;
6557: if (b % Nc == comps[ncind]) {
6558: ncind = (ncind + 1) % Ncc;
6559: ncSet = PETSC_TRUE;
6560: }
6561: if ((cind < fcdof) && (b == fcdofs[cind])) {
6562: ++cind;
6563: fcSet = PETSC_TRUE;
6564: }
6565: if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6566: }
6567: } else {
6568: for (b = 0; b < fdof; b++) {
6569: if ((cind < fcdof) && (b == fcdofs[cind])) {
6570: fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6571: ++cind;
6572: }
6573: }
6574: }
6575: }
6576: }
6577: }
6578: *offset += fdof;
6579: PetscFunctionReturn(PETSC_SUCCESS);
6580: }
6582: static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6583: {
6584: PetscScalar *array;
6585: const PetscInt *cone, *coneO;
6586: PetscInt pStart, pEnd, p, numPoints, off, dof;
6588: PetscFunctionBeginHot;
6589: PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6590: PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
6591: PetscCall(DMPlexGetCone(dm, point, &cone));
6592: PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
6593: PetscCall(VecGetArray(v, &array));
6594: for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6595: const PetscInt cp = !p ? point : cone[p - 1];
6596: const PetscInt o = !p ? 0 : coneO[p - 1];
6598: if ((cp < pStart) || (cp >= pEnd)) {
6599: dof = 0;
6600: continue;
6601: }
6602: PetscCall(PetscSectionGetDof(section, cp, &dof));
6603: /* ADD_VALUES */
6604: {
6605: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6606: PetscScalar *a;
6607: PetscInt cdof, coff, cind = 0, k;
6609: PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
6610: PetscCall(PetscSectionGetOffset(section, cp, &coff));
6611: a = &array[coff];
6612: if (!cdof) {
6613: if (o >= 0) {
6614: for (k = 0; k < dof; ++k) a[k] += values[off + k];
6615: } else {
6616: for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
6617: }
6618: } else {
6619: PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6620: if (o >= 0) {
6621: for (k = 0; k < dof; ++k) {
6622: if ((cind < cdof) && (k == cdofs[cind])) {
6623: ++cind;
6624: continue;
6625: }
6626: a[k] += values[off + k];
6627: }
6628: } else {
6629: for (k = 0; k < dof; ++k) {
6630: if ((cind < cdof) && (k == cdofs[cind])) {
6631: ++cind;
6632: continue;
6633: }
6634: a[k] += values[off + dof - k - 1];
6635: }
6636: }
6637: }
6638: }
6639: }
6640: PetscCall(VecRestoreArray(v, &array));
6641: PetscFunctionReturn(PETSC_SUCCESS);
6642: }
6644: /*@C
6645: DMPlexVecSetClosure - Set an array of the values on the closure of `point`
6647: Not collective
6649: Input Parameters:
6650: + dm - The `DM`
6651: . section - The section describing the layout in `v`, or `NULL` to use the default section
6652: . v - The local vector
6653: . point - The point in the `DM`
6654: . values - The array of values
6655: - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
6656: where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.
6658: Level: intermediate
6660: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
6661: @*/
6662: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6663: {
6664: PetscSection clSection;
6665: IS clPoints;
6666: PetscScalar *array;
6667: PetscInt *points = NULL;
6668: const PetscInt *clp, *clperm = NULL;
6669: PetscInt depth, numFields, numPoints, p, clsize;
6671: PetscFunctionBeginHot;
6673: if (!section) PetscCall(DMGetLocalSection(dm, §ion));
6676: PetscCall(DMPlexGetDepth(dm, &depth));
6677: PetscCall(PetscSectionGetNumFields(section, &numFields));
6678: if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
6679: PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
6680: PetscFunctionReturn(PETSC_SUCCESS);
6681: }
6682: /* Get points */
6683: PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6684: for (clsize = 0, p = 0; p < numPoints; p++) {
6685: PetscInt dof;
6686: PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6687: clsize += dof;
6688: }
6689: PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
6690: /* Get array */
6691: PetscCall(VecGetArray(v, &array));
6692: /* Get values */
6693: if (numFields > 0) {
6694: PetscInt offset = 0, f;
6695: for (f = 0; f < numFields; ++f) {
6696: const PetscInt **perms = NULL;
6697: const PetscScalar **flips = NULL;
6699: PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6700: switch (mode) {
6701: case INSERT_VALUES:
6702: for (p = 0; p < numPoints; p++) {
6703: const PetscInt point = points[2 * p];
6704: const PetscInt *perm = perms ? perms[p] : NULL;
6705: const PetscScalar *flip = flips ? flips[p] : NULL;
6706: PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
6707: }
6708: break;
6709: case INSERT_ALL_VALUES:
6710: for (p = 0; p < numPoints; p++) {
6711: const PetscInt point = points[2 * p];
6712: const PetscInt *perm = perms ? perms[p] : NULL;
6713: const PetscScalar *flip = flips ? flips[p] : NULL;
6714: PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
6715: }
6716: break;
6717: case INSERT_BC_VALUES:
6718: for (p = 0; p < numPoints; p++) {
6719: const PetscInt point = points[2 * p];
6720: const PetscInt *perm = perms ? perms[p] : NULL;
6721: const PetscScalar *flip = flips ? flips[p] : NULL;
6722: PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
6723: }
6724: break;
6725: case ADD_VALUES:
6726: for (p = 0; p < numPoints; p++) {
6727: const PetscInt point = points[2 * p];
6728: const PetscInt *perm = perms ? perms[p] : NULL;
6729: const PetscScalar *flip = flips ? flips[p] : NULL;
6730: PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
6731: }
6732: break;
6733: case ADD_ALL_VALUES:
6734: for (p = 0; p < numPoints; p++) {
6735: const PetscInt point = points[2 * p];
6736: const PetscInt *perm = perms ? perms[p] : NULL;
6737: const PetscScalar *flip = flips ? flips[p] : NULL;
6738: PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
6739: }
6740: break;
6741: case ADD_BC_VALUES:
6742: for (p = 0; p < numPoints; p++) {
6743: const PetscInt point = points[2 * p];
6744: const PetscInt *perm = perms ? perms[p] : NULL;
6745: const PetscScalar *flip = flips ? flips[p] : NULL;
6746: PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
6747: }
6748: break;
6749: default:
6750: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6751: }
6752: PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6753: }
6754: } else {
6755: PetscInt dof, off;
6756: const PetscInt **perms = NULL;
6757: const PetscScalar **flips = NULL;
6759: PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
6760: switch (mode) {
6761: case INSERT_VALUES:
6762: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6763: const PetscInt point = points[2 * p];
6764: const PetscInt *perm = perms ? perms[p] : NULL;
6765: const PetscScalar *flip = flips ? flips[p] : NULL;
6766: PetscCall(PetscSectionGetDof(section, point, &dof));
6767: PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
6768: }
6769: break;
6770: case INSERT_ALL_VALUES:
6771: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6772: const PetscInt point = points[2 * p];
6773: const PetscInt *perm = perms ? perms[p] : NULL;
6774: const PetscScalar *flip = flips ? flips[p] : NULL;
6775: PetscCall(PetscSectionGetDof(section, point, &dof));
6776: PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
6777: }
6778: break;
6779: case INSERT_BC_VALUES:
6780: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6781: const PetscInt point = points[2 * p];
6782: const PetscInt *perm = perms ? perms[p] : NULL;
6783: const PetscScalar *flip = flips ? flips[p] : NULL;
6784: PetscCall(PetscSectionGetDof(section, point, &dof));
6785: PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
6786: }
6787: break;
6788: case ADD_VALUES:
6789: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6790: const PetscInt point = points[2 * p];
6791: const PetscInt *perm = perms ? perms[p] : NULL;
6792: const PetscScalar *flip = flips ? flips[p] : NULL;
6793: PetscCall(PetscSectionGetDof(section, point, &dof));
6794: PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
6795: }
6796: break;
6797: case ADD_ALL_VALUES:
6798: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6799: const PetscInt point = points[2 * p];
6800: const PetscInt *perm = perms ? perms[p] : NULL;
6801: const PetscScalar *flip = flips ? flips[p] : NULL;
6802: PetscCall(PetscSectionGetDof(section, point, &dof));
6803: PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
6804: }
6805: break;
6806: case ADD_BC_VALUES:
6807: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6808: const PetscInt point = points[2 * p];
6809: const PetscInt *perm = perms ? perms[p] : NULL;
6810: const PetscScalar *flip = flips ? flips[p] : NULL;
6811: PetscCall(PetscSectionGetDof(section, point, &dof));
6812: PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
6813: }
6814: break;
6815: default:
6816: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6817: }
6818: PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
6819: }
6820: /* Cleanup points */
6821: PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6822: /* Cleanup array */
6823: PetscCall(VecRestoreArray(v, &array));
6824: PetscFunctionReturn(PETSC_SUCCESS);
6825: }
6827: /* Check whether the given point is in the label. If not, update the offset to skip this point */
6828: static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
6829: {
6830: PetscFunctionBegin;
6831: *contains = PETSC_TRUE;
6832: if (label) {
6833: PetscInt fdof;
6835: PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
6836: if (!*contains) {
6837: PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6838: *offset += fdof;
6839: PetscFunctionReturn(PETSC_SUCCESS);
6840: }
6841: }
6842: PetscFunctionReturn(PETSC_SUCCESS);
6843: }
6845: /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6846: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt labelId, const PetscScalar values[], InsertMode mode)
6847: {
6848: PetscSection clSection;
6849: IS clPoints;
6850: PetscScalar *array;
6851: PetscInt *points = NULL;
6852: const PetscInt *clp;
6853: PetscInt numFields, numPoints, p;
6854: PetscInt offset = 0, f;
6856: PetscFunctionBeginHot;
6858: if (!section) PetscCall(DMGetLocalSection(dm, §ion));
6861: PetscCall(PetscSectionGetNumFields(section, &numFields));
6862: /* Get points */
6863: PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6864: /* Get array */
6865: PetscCall(VecGetArray(v, &array));
6866: /* Get values */
6867: for (f = 0; f < numFields; ++f) {
6868: const PetscInt **perms = NULL;
6869: const PetscScalar **flips = NULL;
6870: PetscBool contains;
6872: if (!fieldActive[f]) {
6873: for (p = 0; p < numPoints * 2; p += 2) {
6874: PetscInt fdof;
6875: PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
6876: offset += fdof;
6877: }
6878: continue;
6879: }
6880: PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6881: switch (mode) {
6882: case INSERT_VALUES:
6883: for (p = 0; p < numPoints; p++) {
6884: const PetscInt point = points[2 * p];
6885: const PetscInt *perm = perms ? perms[p] : NULL;
6886: const PetscScalar *flip = flips ? flips[p] : NULL;
6887: PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6888: if (!contains) continue;
6889: PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
6890: }
6891: break;
6892: case INSERT_ALL_VALUES:
6893: for (p = 0; p < numPoints; p++) {
6894: const PetscInt point = points[2 * p];
6895: const PetscInt *perm = perms ? perms[p] : NULL;
6896: const PetscScalar *flip = flips ? flips[p] : NULL;
6897: PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6898: if (!contains) continue;
6899: PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
6900: }
6901: break;
6902: case INSERT_BC_VALUES:
6903: for (p = 0; p < numPoints; p++) {
6904: const PetscInt point = points[2 * p];
6905: const PetscInt *perm = perms ? perms[p] : NULL;
6906: const PetscScalar *flip = flips ? flips[p] : NULL;
6907: PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6908: if (!contains) continue;
6909: PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
6910: }
6911: break;
6912: case ADD_VALUES:
6913: for (p = 0; p < numPoints; p++) {
6914: const PetscInt point = points[2 * p];
6915: const PetscInt *perm = perms ? perms[p] : NULL;
6916: const PetscScalar *flip = flips ? flips[p] : NULL;
6917: PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6918: if (!contains) continue;
6919: PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
6920: }
6921: break;
6922: case ADD_ALL_VALUES:
6923: for (p = 0; p < numPoints; p++) {
6924: const PetscInt point = points[2 * p];
6925: const PetscInt *perm = perms ? perms[p] : NULL;
6926: const PetscScalar *flip = flips ? flips[p] : NULL;
6927: PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6928: if (!contains) continue;
6929: PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
6930: }
6931: break;
6932: default:
6933: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6934: }
6935: PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6936: }
6937: /* Cleanup points */
6938: PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6939: /* Cleanup array */
6940: PetscCall(VecRestoreArray(v, &array));
6941: PetscFunctionReturn(PETSC_SUCCESS);
6942: }
6944: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6945: {
6946: PetscMPIInt rank;
6947: PetscInt i, j;
6949: PetscFunctionBegin;
6950: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
6951: PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
6952: for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
6953: for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
6954: numCIndices = numCIndices ? numCIndices : numRIndices;
6955: if (!values) PetscFunctionReturn(PETSC_SUCCESS);
6956: for (i = 0; i < numRIndices; i++) {
6957: PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
6958: for (j = 0; j < numCIndices; j++) {
6959: #if defined(PETSC_USE_COMPLEX)
6960: PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
6961: #else
6962: PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
6963: #endif
6964: }
6965: PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
6966: }
6967: PetscFunctionReturn(PETSC_SUCCESS);
6968: }
6970: /*
6971: DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
6973: Input Parameters:
6974: + section - The section for this data layout
6975: . islocal - Is the section (and thus indices being requested) local or global?
6976: . point - The point contributing dofs with these indices
6977: . off - The global offset of this point
6978: . loff - The local offset of each field
6979: . setBC - The flag determining whether to include indices of boundary values
6980: . perm - A permutation of the dofs on this point, or NULL
6981: - indperm - A permutation of the entire indices array, or NULL
6983: Output Parameter:
6984: . indices - Indices for dofs on this point
6986: Level: developer
6988: Note: The indices could be local or global, depending on the value of 'off'.
6989: */
6990: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6991: {
6992: PetscInt dof; /* The number of unknowns on this point */
6993: PetscInt cdof; /* The number of constraints on this point */
6994: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6995: PetscInt cind = 0, k;
6997: PetscFunctionBegin;
6998: PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
6999: PetscCall(PetscSectionGetDof(section, point, &dof));
7000: PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7001: if (!cdof || setBC) {
7002: for (k = 0; k < dof; ++k) {
7003: const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7004: const PetscInt ind = indperm ? indperm[preind] : preind;
7006: indices[ind] = off + k;
7007: }
7008: } else {
7009: PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
7010: for (k = 0; k < dof; ++k) {
7011: const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7012: const PetscInt ind = indperm ? indperm[preind] : preind;
7014: if ((cind < cdof) && (k == cdofs[cind])) {
7015: /* Insert check for returning constrained indices */
7016: indices[ind] = -(off + k + 1);
7017: ++cind;
7018: } else {
7019: indices[ind] = off + k - (islocal ? 0 : cind);
7020: }
7021: }
7022: }
7023: *loff += dof;
7024: PetscFunctionReturn(PETSC_SUCCESS);
7025: }
7027: /*
7028: DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
7030: Input Parameters:
7031: + section - a section (global or local)
7032: - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
7033: . point - point within section
7034: . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
7035: . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
7036: . setBC - identify constrained (boundary condition) points via involution.
7037: . perms - perms[f][permsoff][:] is a permutation of dofs within each field
7038: . permsoff - offset
7039: - indperm - index permutation
7041: Output Parameter:
7042: . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
7043: . indices - array to hold indices (as defined by section) of each dof associated with point
7045: Notes:
7046: If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
7047: If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
7048: in the local vector.
7050: If section is global and setBC=false, the indices for constrained points are negative (and their value is not
7051: significant). It is invalid to call with a global section and setBC=true.
7053: Developer Note:
7054: The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point
7055: in the future, global sections may have fields set, in which case we could pass the global section and obtain the
7056: offset could be obtained from the section instead of passing it explicitly as we do now.
7058: Example:
7059: Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
7060: When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
7061: Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
7062: The global vector does not store constrained dofs, so when this function returns global indices, say {110, -112, 111}, the value of -112 is an arbitrary flag that should not be interpreted beyond its sign.
7064: Level: developer
7065: */
7066: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7067: {
7068: PetscInt numFields, foff, f;
7070: PetscFunctionBegin;
7071: PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
7072: PetscCall(PetscSectionGetNumFields(section, &numFields));
7073: for (f = 0, foff = 0; f < numFields; ++f) {
7074: PetscInt fdof, cfdof;
7075: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7076: PetscInt cind = 0, b;
7077: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7079: PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7080: PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7081: if (!cfdof || setBC) {
7082: for (b = 0; b < fdof; ++b) {
7083: const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7084: const PetscInt ind = indperm ? indperm[preind] : preind;
7086: indices[ind] = off + foff + b;
7087: }
7088: } else {
7089: PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7090: for (b = 0; b < fdof; ++b) {
7091: const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7092: const PetscInt ind = indperm ? indperm[preind] : preind;
7094: if ((cind < cfdof) && (b == fcdofs[cind])) {
7095: indices[ind] = -(off + foff + b + 1);
7096: ++cind;
7097: } else {
7098: indices[ind] = off + foff + b - (islocal ? 0 : cind);
7099: }
7100: }
7101: }
7102: foff += (setBC || islocal ? fdof : (fdof - cfdof));
7103: foffs[f] += fdof;
7104: }
7105: PetscFunctionReturn(PETSC_SUCCESS);
7106: }
7108: /*
7109: This version believes the globalSection offsets for each field, rather than just the point offset
7111: . foffs - The offset into 'indices' for each field, since it is segregated by field
7113: Notes:
7114: The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7115: Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
7116: */
7117: static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7118: {
7119: PetscInt numFields, foff, f;
7121: PetscFunctionBegin;
7122: PetscCall(PetscSectionGetNumFields(section, &numFields));
7123: for (f = 0; f < numFields; ++f) {
7124: PetscInt fdof, cfdof;
7125: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7126: PetscInt cind = 0, b;
7127: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
7129: PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7130: PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7131: PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7132: if (!cfdof) {
7133: for (b = 0; b < fdof; ++b) {
7134: const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7135: const PetscInt ind = indperm ? indperm[preind] : preind;
7137: indices[ind] = foff + b;
7138: }
7139: } else {
7140: PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7141: for (b = 0; b < fdof; ++b) {
7142: const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7143: const PetscInt ind = indperm ? indperm[preind] : preind;
7145: if ((cind < cfdof) && (b == fcdofs[cind])) {
7146: indices[ind] = -(foff + b + 1);
7147: ++cind;
7148: } else {
7149: indices[ind] = foff + b - cind;
7150: }
7151: }
7152: }
7153: foffs[f] += fdof;
7154: }
7155: PetscFunctionReturn(PETSC_SUCCESS);
7156: }
7158: PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft)
7159: {
7160: Mat cMat;
7161: PetscSection aSec, cSec;
7162: IS aIS;
7163: PetscInt aStart = -1, aEnd = -1;
7164: const PetscInt *anchors;
7165: PetscInt numFields, f, p, q, newP = 0;
7166: PetscInt newNumPoints = 0, newNumIndices = 0;
7167: PetscInt *newPoints, *indices, *newIndices;
7168: PetscInt maxAnchor, maxDof;
7169: PetscInt newOffsets[32];
7170: PetscInt *pointMatOffsets[32];
7171: PetscInt *newPointOffsets[32];
7172: PetscScalar *pointMat[32];
7173: PetscScalar *newValues = NULL, *tmpValues;
7174: PetscBool anyConstrained = PETSC_FALSE;
7176: PetscFunctionBegin;
7179: PetscCall(PetscSectionGetNumFields(section, &numFields));
7181: PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7182: /* if there are point-to-point constraints */
7183: if (aSec) {
7184: PetscCall(PetscArrayzero(newOffsets, 32));
7185: PetscCall(ISGetIndices(aIS, &anchors));
7186: PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7187: /* figure out how many points are going to be in the new element matrix
7188: * (we allow double counting, because it's all just going to be summed
7189: * into the global matrix anyway) */
7190: for (p = 0; p < 2 * numPoints; p += 2) {
7191: PetscInt b = points[p];
7192: PetscInt bDof = 0, bSecDof;
7194: PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7195: if (!bSecDof) continue;
7196: if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7197: if (bDof) {
7198: /* this point is constrained */
7199: /* it is going to be replaced by its anchors */
7200: PetscInt bOff, q;
7202: anyConstrained = PETSC_TRUE;
7203: newNumPoints += bDof;
7204: PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7205: for (q = 0; q < bDof; q++) {
7206: PetscInt a = anchors[bOff + q];
7207: PetscInt aDof;
7209: PetscCall(PetscSectionGetDof(section, a, &aDof));
7210: newNumIndices += aDof;
7211: for (f = 0; f < numFields; ++f) {
7212: PetscInt fDof;
7214: PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7215: newOffsets[f + 1] += fDof;
7216: }
7217: }
7218: } else {
7219: /* this point is not constrained */
7220: newNumPoints++;
7221: newNumIndices += bSecDof;
7222: for (f = 0; f < numFields; ++f) {
7223: PetscInt fDof;
7225: PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7226: newOffsets[f + 1] += fDof;
7227: }
7228: }
7229: }
7230: }
7231: if (!anyConstrained) {
7232: if (outNumPoints) *outNumPoints = 0;
7233: if (outNumIndices) *outNumIndices = 0;
7234: if (outPoints) *outPoints = NULL;
7235: if (outValues) *outValues = NULL;
7236: if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7237: PetscFunctionReturn(PETSC_SUCCESS);
7238: }
7240: if (outNumPoints) *outNumPoints = newNumPoints;
7241: if (outNumIndices) *outNumIndices = newNumIndices;
7243: for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f];
7245: if (!outPoints && !outValues) {
7246: if (offsets) {
7247: for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7248: }
7249: if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7250: PetscFunctionReturn(PETSC_SUCCESS);
7251: }
7253: PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices);
7255: PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
7257: /* workspaces */
7258: if (numFields) {
7259: for (f = 0; f < numFields; f++) {
7260: PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
7261: PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7262: }
7263: } else {
7264: PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
7265: PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0]));
7266: }
7268: /* get workspaces for the point-to-point matrices */
7269: if (numFields) {
7270: PetscInt totalOffset, totalMatOffset;
7272: for (p = 0; p < numPoints; p++) {
7273: PetscInt b = points[2 * p];
7274: PetscInt bDof = 0, bSecDof;
7276: PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7277: if (!bSecDof) {
7278: for (f = 0; f < numFields; f++) {
7279: newPointOffsets[f][p + 1] = 0;
7280: pointMatOffsets[f][p + 1] = 0;
7281: }
7282: continue;
7283: }
7284: if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7285: if (bDof) {
7286: for (f = 0; f < numFields; f++) {
7287: PetscInt fDof, q, bOff, allFDof = 0;
7289: PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7290: PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7291: for (q = 0; q < bDof; q++) {
7292: PetscInt a = anchors[bOff + q];
7293: PetscInt aFDof;
7295: PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof));
7296: allFDof += aFDof;
7297: }
7298: newPointOffsets[f][p + 1] = allFDof;
7299: pointMatOffsets[f][p + 1] = fDof * allFDof;
7300: }
7301: } else {
7302: for (f = 0; f < numFields; f++) {
7303: PetscInt fDof;
7305: PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7306: newPointOffsets[f][p + 1] = fDof;
7307: pointMatOffsets[f][p + 1] = 0;
7308: }
7309: }
7310: }
7311: for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
7312: newPointOffsets[f][0] = totalOffset;
7313: pointMatOffsets[f][0] = totalMatOffset;
7314: for (p = 0; p < numPoints; p++) {
7315: newPointOffsets[f][p + 1] += newPointOffsets[f][p];
7316: pointMatOffsets[f][p + 1] += pointMatOffsets[f][p];
7317: }
7318: totalOffset = newPointOffsets[f][numPoints];
7319: totalMatOffset = pointMatOffsets[f][numPoints];
7320: PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
7321: }
7322: } else {
7323: for (p = 0; p < numPoints; p++) {
7324: PetscInt b = points[2 * p];
7325: PetscInt bDof = 0, bSecDof;
7327: PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7328: if (!bSecDof) {
7329: newPointOffsets[0][p + 1] = 0;
7330: pointMatOffsets[0][p + 1] = 0;
7331: continue;
7332: }
7333: if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7334: if (bDof) {
7335: PetscInt bOff, q, allDof = 0;
7337: PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7338: for (q = 0; q < bDof; q++) {
7339: PetscInt a = anchors[bOff + q], aDof;
7341: PetscCall(PetscSectionGetDof(section, a, &aDof));
7342: allDof += aDof;
7343: }
7344: newPointOffsets[0][p + 1] = allDof;
7345: pointMatOffsets[0][p + 1] = bSecDof * allDof;
7346: } else {
7347: newPointOffsets[0][p + 1] = bSecDof;
7348: pointMatOffsets[0][p + 1] = 0;
7349: }
7350: }
7351: newPointOffsets[0][0] = 0;
7352: pointMatOffsets[0][0] = 0;
7353: for (p = 0; p < numPoints; p++) {
7354: newPointOffsets[0][p + 1] += newPointOffsets[0][p];
7355: pointMatOffsets[0][p + 1] += pointMatOffsets[0][p];
7356: }
7357: PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
7358: }
7360: /* output arrays */
7361: PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7363: /* get the point-to-point matrices; construct newPoints */
7364: PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor));
7365: PetscCall(PetscSectionGetMaxDof(section, &maxDof));
7366: PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices));
7367: PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
7368: if (numFields) {
7369: for (p = 0, newP = 0; p < numPoints; p++) {
7370: PetscInt b = points[2 * p];
7371: PetscInt o = points[2 * p + 1];
7372: PetscInt bDof = 0, bSecDof;
7374: PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7375: if (!bSecDof) continue;
7376: if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7377: if (bDof) {
7378: PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
7380: fStart[0] = 0;
7381: fEnd[0] = 0;
7382: for (f = 0; f < numFields; f++) {
7383: PetscInt fDof;
7385: PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof));
7386: fStart[f + 1] = fStart[f] + fDof;
7387: fEnd[f + 1] = fStart[f + 1];
7388: }
7389: PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
7390: PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices));
7392: fAnchorStart[0] = 0;
7393: fAnchorEnd[0] = 0;
7394: for (f = 0; f < numFields; f++) {
7395: PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
7397: fAnchorStart[f + 1] = fAnchorStart[f] + fDof;
7398: fAnchorEnd[f + 1] = fAnchorStart[f + 1];
7399: }
7400: PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7401: for (q = 0; q < bDof; q++) {
7402: PetscInt a = anchors[bOff + q], aOff;
7404: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7405: newPoints[2 * (newP + q)] = a;
7406: newPoints[2 * (newP + q) + 1] = 0;
7407: PetscCall(PetscSectionGetOffset(section, a, &aOff));
7408: PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices));
7409: }
7410: newP += bDof;
7412: if (outValues) {
7413: /* get the point-to-point submatrix */
7414: for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p]));
7415: }
7416: } else {
7417: newPoints[2 * newP] = b;
7418: newPoints[2 * newP + 1] = o;
7419: newP++;
7420: }
7421: }
7422: } else {
7423: for (p = 0; p < numPoints; p++) {
7424: PetscInt b = points[2 * p];
7425: PetscInt o = points[2 * p + 1];
7426: PetscInt bDof = 0, bSecDof;
7428: PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7429: if (!bSecDof) continue;
7430: if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7431: if (bDof) {
7432: PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7434: PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
7435: PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices));
7437: PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7438: for (q = 0; q < bDof; q++) {
7439: PetscInt a = anchors[bOff + q], aOff;
7441: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7443: newPoints[2 * (newP + q)] = a;
7444: newPoints[2 * (newP + q) + 1] = 0;
7445: PetscCall(PetscSectionGetOffset(section, a, &aOff));
7446: PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices));
7447: }
7448: newP += bDof;
7450: /* get the point-to-point submatrix */
7451: if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p]));
7452: } else {
7453: newPoints[2 * newP] = b;
7454: newPoints[2 * newP + 1] = o;
7455: newP++;
7456: }
7457: }
7458: }
7460: if (outValues) {
7461: PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
7462: PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices));
7463: /* multiply constraints on the right */
7464: if (numFields) {
7465: for (f = 0; f < numFields; f++) {
7466: PetscInt oldOff = offsets[f];
7468: for (p = 0; p < numPoints; p++) {
7469: PetscInt cStart = newPointOffsets[f][p];
7470: PetscInt b = points[2 * p];
7471: PetscInt c, r, k;
7472: PetscInt dof;
7474: PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7475: if (!dof) continue;
7476: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7477: PetscInt nCols = newPointOffsets[f][p + 1] - cStart;
7478: const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
7480: for (r = 0; r < numIndices; r++) {
7481: for (c = 0; c < nCols; c++) {
7482: for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7483: }
7484: }
7485: } else {
7486: /* copy this column as is */
7487: for (r = 0; r < numIndices; r++) {
7488: for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7489: }
7490: }
7491: oldOff += dof;
7492: }
7493: }
7494: } else {
7495: PetscInt oldOff = 0;
7496: for (p = 0; p < numPoints; p++) {
7497: PetscInt cStart = newPointOffsets[0][p];
7498: PetscInt b = points[2 * p];
7499: PetscInt c, r, k;
7500: PetscInt dof;
7502: PetscCall(PetscSectionGetDof(section, b, &dof));
7503: if (!dof) continue;
7504: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7505: PetscInt nCols = newPointOffsets[0][p + 1] - cStart;
7506: const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
7508: for (r = 0; r < numIndices; r++) {
7509: for (c = 0; c < nCols; c++) {
7510: for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7511: }
7512: }
7513: } else {
7514: /* copy this column as is */
7515: for (r = 0; r < numIndices; r++) {
7516: for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7517: }
7518: }
7519: oldOff += dof;
7520: }
7521: }
7523: if (multiplyLeft) {
7524: PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues));
7525: PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices));
7526: /* multiply constraints transpose on the left */
7527: if (numFields) {
7528: for (f = 0; f < numFields; f++) {
7529: PetscInt oldOff = offsets[f];
7531: for (p = 0; p < numPoints; p++) {
7532: PetscInt rStart = newPointOffsets[f][p];
7533: PetscInt b = points[2 * p];
7534: PetscInt c, r, k;
7535: PetscInt dof;
7537: PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7538: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7539: PetscInt nRows = newPointOffsets[f][p + 1] - rStart;
7540: const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
7542: for (r = 0; r < nRows; r++) {
7543: for (c = 0; c < newNumIndices; c++) {
7544: for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7545: }
7546: }
7547: } else {
7548: /* copy this row as is */
7549: for (r = 0; r < dof; r++) {
7550: for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7551: }
7552: }
7553: oldOff += dof;
7554: }
7555: }
7556: } else {
7557: PetscInt oldOff = 0;
7559: for (p = 0; p < numPoints; p++) {
7560: PetscInt rStart = newPointOffsets[0][p];
7561: PetscInt b = points[2 * p];
7562: PetscInt c, r, k;
7563: PetscInt dof;
7565: PetscCall(PetscSectionGetDof(section, b, &dof));
7566: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7567: PetscInt nRows = newPointOffsets[0][p + 1] - rStart;
7568: const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
7570: for (r = 0; r < nRows; r++) {
7571: for (c = 0; c < newNumIndices; c++) {
7572: for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7573: }
7574: }
7575: } else {
7576: /* copy this row as is */
7577: for (r = 0; r < dof; r++) {
7578: for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7579: }
7580: }
7581: oldOff += dof;
7582: }
7583: }
7585: PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
7586: } else {
7587: newValues = tmpValues;
7588: }
7589: }
7591: /* clean up */
7592: PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices));
7593: PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
7595: if (numFields) {
7596: for (f = 0; f < numFields; f++) {
7597: PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
7598: PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
7599: PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7600: }
7601: } else {
7602: PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
7603: PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
7604: PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0]));
7605: }
7606: PetscCall(ISRestoreIndices(aIS, &anchors));
7608: /* output */
7609: if (outPoints) {
7610: *outPoints = newPoints;
7611: } else {
7612: PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7613: }
7614: if (outValues) *outValues = newValues;
7615: for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7616: PetscFunctionReturn(PETSC_SUCCESS);
7617: }
7619: /*@C
7620: DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
7622: Not collective
7624: Input Parameters:
7625: + dm - The `DM`
7626: . section - The `PetscSection` describing the points (a local section)
7627: . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
7628: . point - The point defining the closure
7629: - useClPerm - Use the closure point permutation if available
7631: Output Parameters:
7632: + numIndices - The number of dof indices in the closure of point with the input sections
7633: . indices - The dof indices
7634: . outOffsets - Array to write the field offsets into, or `NULL`
7635: - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
7637: Level: advanced
7639: Notes:
7640: Must call `DMPlexRestoreClosureIndices()` to free allocated memory
7642: If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value
7643: of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1)
7644: of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative
7645: indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global
7646: indices (with the above semantics) are implied.
7648: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`,
7649: `PetscSection`, `DMGetGlobalSection()`
7650: @*/
7651: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7652: {
7653: /* Closure ordering */
7654: PetscSection clSection;
7655: IS clPoints;
7656: const PetscInt *clp;
7657: PetscInt *points;
7658: const PetscInt *clperm = NULL;
7659: /* Dof permutation and sign flips */
7660: const PetscInt **perms[32] = {NULL};
7661: const PetscScalar **flips[32] = {NULL};
7662: PetscScalar *valCopy = NULL;
7663: /* Hanging node constraints */
7664: PetscInt *pointsC = NULL;
7665: PetscScalar *valuesC = NULL;
7666: PetscInt NclC, NiC;
7668: PetscInt *idx;
7669: PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f;
7670: PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
7672: PetscFunctionBeginHot;
7676: if (numIndices) PetscAssertPointer(numIndices, 6);
7677: if (indices) PetscAssertPointer(indices, 7);
7678: if (outOffsets) PetscAssertPointer(outOffsets, 8);
7679: if (values) PetscAssertPointer(values, 9);
7680: PetscCall(PetscSectionGetNumFields(section, &Nf));
7681: PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
7682: PetscCall(PetscArrayzero(offsets, 32));
7683: /* 1) Get points in closure */
7684: PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7685: if (useClPerm) {
7686: PetscInt depth, clsize;
7687: PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7688: for (clsize = 0, p = 0; p < Ncl; p++) {
7689: PetscInt dof;
7690: PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7691: clsize += dof;
7692: }
7693: PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7694: }
7695: /* 2) Get number of indices on these points and field offsets from section */
7696: for (p = 0; p < Ncl * 2; p += 2) {
7697: PetscInt dof, fdof;
7699: PetscCall(PetscSectionGetDof(section, points[p], &dof));
7700: for (f = 0; f < Nf; ++f) {
7701: PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7702: offsets[f + 1] += fdof;
7703: }
7704: Ni += dof;
7705: }
7706: for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
7707: PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni);
7708: /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
7709: for (f = 0; f < PetscMax(1, Nf); ++f) {
7710: if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7711: else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
7712: /* may need to apply sign changes to the element matrix */
7713: if (values && flips[f]) {
7714: PetscInt foffset = offsets[f];
7716: for (p = 0; p < Ncl; ++p) {
7717: PetscInt pnt = points[2 * p], fdof;
7718: const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
7720: if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
7721: else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
7722: if (flip) {
7723: PetscInt i, j, k;
7725: if (!valCopy) {
7726: PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
7727: for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
7728: *values = valCopy;
7729: }
7730: for (i = 0; i < fdof; ++i) {
7731: PetscScalar fval = flip[i];
7733: for (k = 0; k < Ni; ++k) {
7734: valCopy[Ni * (foffset + i) + k] *= fval;
7735: valCopy[Ni * k + (foffset + i)] *= fval;
7736: }
7737: }
7738: }
7739: foffset += fdof;
7740: }
7741: }
7742: }
7743: /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
7744: PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE));
7745: if (NclC) {
7746: if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
7747: for (f = 0; f < PetscMax(1, Nf); ++f) {
7748: if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7749: else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
7750: }
7751: for (f = 0; f < PetscMax(1, Nf); ++f) {
7752: if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
7753: else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
7754: }
7755: PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7756: Ncl = NclC;
7757: Ni = NiC;
7758: points = pointsC;
7759: if (values) *values = valuesC;
7760: }
7761: /* 5) Calculate indices */
7762: PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
7763: if (Nf) {
7764: PetscInt idxOff;
7765: PetscBool useFieldOffsets;
7767: if (outOffsets) {
7768: for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
7769: }
7770: PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
7771: if (useFieldOffsets) {
7772: for (p = 0; p < Ncl; ++p) {
7773: const PetscInt pnt = points[p * 2];
7775: PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
7776: }
7777: } else {
7778: for (p = 0; p < Ncl; ++p) {
7779: const PetscInt pnt = points[p * 2];
7781: PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
7782: /* Note that we pass a local section even though we're using global offsets. This is because global sections do
7783: * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
7784: * global section. */
7785: PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
7786: }
7787: }
7788: } else {
7789: PetscInt off = 0, idxOff;
7791: for (p = 0; p < Ncl; ++p) {
7792: const PetscInt pnt = points[p * 2];
7793: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
7795: PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
7796: /* Note that we pass a local section even though we're using global offsets. This is because global sections do
7797: * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
7798: PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
7799: }
7800: }
7801: /* 6) Cleanup */
7802: for (f = 0; f < PetscMax(1, Nf); ++f) {
7803: if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7804: else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
7805: }
7806: if (NclC) {
7807: PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
7808: } else {
7809: PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7810: }
7812: if (numIndices) *numIndices = Ni;
7813: if (indices) *indices = idx;
7814: PetscFunctionReturn(PETSC_SUCCESS);
7815: }
7817: /*@C
7818: DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
7820: Not collective
7822: Input Parameters:
7823: + dm - The `DM`
7824: . section - The `PetscSection` describing the points (a local section)
7825: . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
7826: . point - The point defining the closure
7827: - useClPerm - Use the closure point permutation if available
7829: Output Parameters:
7830: + numIndices - The number of dof indices in the closure of point with the input sections
7831: . indices - The dof indices
7832: . outOffsets - Array to write the field offsets into, or `NULL`
7833: - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`
7835: Level: advanced
7837: Notes:
7838: If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values).
7840: If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value
7841: of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7842: of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative
7843: indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global
7844: indices (with the above semantics) are implied.
7846: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
7847: @*/
7848: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7849: {
7850: PetscFunctionBegin;
7852: PetscAssertPointer(indices, 7);
7853: PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
7854: PetscFunctionReturn(PETSC_SUCCESS);
7855: }
7857: PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7858: {
7859: DM_Plex *mesh = (DM_Plex *)dm->data;
7860: PetscInt *indices;
7861: PetscInt numIndices;
7862: const PetscScalar *valuesOrig = values;
7863: PetscErrorCode ierr;
7865: PetscFunctionBegin;
7867: if (!section) PetscCall(DMGetLocalSection(dm, §ion));
7869: if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));
7873: PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values));
7875: if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
7876: /* TODO: fix this code to not use error codes as handle-able exceptions! */
7877: ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7878: if (ierr) {
7879: PetscMPIInt rank;
7881: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7882: PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
7883: PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
7884: PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
7885: if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7886: SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
7887: }
7888: if (mesh->printFEM > 1) {
7889: PetscInt i;
7890: PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:"));
7891: for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
7892: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
7893: }
7895: PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
7896: if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7897: PetscFunctionReturn(PETSC_SUCCESS);
7898: }
7900: /*@C
7901: DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
7903: Not collective
7905: Input Parameters:
7906: + dm - The `DM`
7907: . section - The section describing the layout in `v`, or `NULL` to use the default section
7908: . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section
7909: . A - The matrix
7910: . point - The point in the `DM`
7911: . values - The array of values
7912: - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
7914: Level: intermediate
7916: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
7917: @*/
7918: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7919: {
7920: PetscFunctionBegin;
7921: PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode));
7922: PetscFunctionReturn(PETSC_SUCCESS);
7923: }
7925: /*@C
7926: DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section
7928: Not collective
7930: Input Parameters:
7931: + dmRow - The `DM` for the row fields
7932: . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow`
7933: . useRowPerm - The flag to use the closure permutation of the `dmRow` if available
7934: . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow`
7935: . dmCol - The `DM` for the column fields
7936: . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol`
7937: . useColPerm - The flag to use the closure permutation of the `dmCol` if available
7938: . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol`
7939: . A - The matrix
7940: . point - The point in the `DM`
7941: . values - The array of values
7942: - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions
7944: Level: intermediate
7946: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
7947: @*/
7948: PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, PetscBool useRowPerm, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, PetscBool useColPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7949: {
7950: DM_Plex *mesh = (DM_Plex *)dmRow->data;
7951: PetscInt *indicesRow, *indicesCol;
7952: PetscInt numIndicesRow, numIndicesCol;
7953: const PetscScalar *valuesOrig = values;
7954: PetscErrorCode ierr;
7956: PetscFunctionBegin;
7958: if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow));
7960: if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
7963: if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol));
7965: if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));
7969: PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
7970: PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
7972: if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7973: /* TODO: fix this code to not use error codes as handle-able exceptions! */
7974: ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
7975: if (ierr) {
7976: PetscMPIInt rank;
7978: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7979: PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
7980: PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7981: PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
7982: PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values));
7983: if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7984: }
7986: PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
7987: PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
7988: if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7989: PetscFunctionReturn(PETSC_SUCCESS);
7990: }
7992: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7993: {
7994: DM_Plex *mesh = (DM_Plex *)dmf->data;
7995: PetscInt *fpoints = NULL, *ftotpoints = NULL;
7996: PetscInt *cpoints = NULL;
7997: PetscInt *findices, *cindices;
7998: const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7999: PetscInt foffsets[32], coffsets[32];
8000: DMPolytopeType ct;
8001: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8002: PetscErrorCode ierr;
8004: PetscFunctionBegin;
8007: if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8009: if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8011: if (!globalFSection)