Actual source code: plex.c
petsc-dev 2014-02-02
1: #include <petsc-private/dmpleximpl.h> /*I "petscdmplex.h" I*/
2: #include <../src/sys/utils/hash.h>
3: #include <petsc-private/isimpl.h>
4: #include <petscsf.h>
6: /* Logging support */
7: PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM;
9: PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
10: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
14: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
15: {
16: DM dm;
17: PetscBool isvtk;
21: VecGetDM(v, &dm);
22: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
23: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
24: if (isvtk) {
25: PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
26: PetscSection section;
27: PetscInt dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
29: DMPlexGetDimension(dm, &dim);
30: DMGetDefaultSection(dm, §ion);
31: DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
32: DMPlexGetHeightStratum(dm, 1, &fStart, NULL);
33: DMPlexGetDepthStratum(dm, 0, &vStart, NULL);
34: PetscSectionGetChart(section, &pStart, &pEnd);
35: /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
36: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &cdof);}
37: if ((fStart >= pStart) && (fStart < pEnd)) {PetscSectionGetDof(section, fStart, &fdof);}
38: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vdof);}
39: if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
40: ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
41: } else if (cdof && vdof) {
42: SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
43: } else if (cdof) {
44: /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
45: * vector or just happens to have the same number of dofs as the dimension. */
46: if (cdof == dim) {
47: ft = PETSC_VTK_CELL_VECTOR_FIELD;
48: } else {
49: ft = PETSC_VTK_CELL_FIELD;
50: }
51: } else if (vdof) {
52: if (vdof == dim) {
53: ft = PETSC_VTK_POINT_VECTOR_FIELD;
54: } else {
55: ft = PETSC_VTK_POINT_FIELD;
56: }
57: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
59: PetscObjectReference((PetscObject) dm); /* viewer drops reference */
60: PetscObjectReference((PetscObject) v); /* viewer drops reference */
61: PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
62: } else {
63: PetscBool isseq;
65: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
66: if (isseq) {
67: VecView_Seq(v, viewer);
68: } else {
69: VecView_MPI(v, viewer);
70: }
71: }
72: return(0);
73: }
77: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
78: {
79: DM dm;
80: PetscBool isvtk;
84: VecGetDM(v, &dm);
85: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
86: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
87: if (isvtk) {
88: Vec locv;
89: const char *name;
91: DMGetLocalVector(dm, &locv);
92: PetscObjectGetName((PetscObject) v, &name);
93: PetscObjectSetName((PetscObject) locv, name);
94: DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
95: DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
96: VecView_Plex_Local(locv, viewer);
97: DMRestoreLocalVector(dm, &locv);
98: } else {
99: PetscBool isseq;
101: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
102: if (isseq) {
103: VecView_Seq(v, viewer);
104: } else {
105: VecView_MPI(v, viewer);
106: }
107: }
108: return(0);
109: }
113: PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
114: {
115: DM_Plex *mesh = (DM_Plex*) dm->data;
116: DM cdm;
117: DMLabel markers;
118: PetscSection coordSection;
119: Vec coordinates;
120: PetscViewerFormat format;
121: PetscErrorCode ierr;
124: DMGetCoordinateDM(dm, &cdm);
125: DMGetDefaultSection(cdm, &coordSection);
126: DMGetCoordinatesLocal(dm, &coordinates);
127: PetscViewerGetFormat(viewer, &format);
128: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
129: const char *name;
130: PetscInt maxConeSize, maxSupportSize;
131: PetscInt pStart, pEnd, p;
132: PetscMPIInt rank, size;
134: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
135: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
136: PetscObjectGetName((PetscObject) dm, &name);
137: DMPlexGetChart(dm, &pStart, &pEnd);
138: DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
139: PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);
140: PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);
141: PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);
142: PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
143: PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
144: for (p = pStart; p < pEnd; ++p) {
145: PetscInt dof, off, s;
147: PetscSectionGetDof(mesh->supportSection, p, &dof);
148: PetscSectionGetOffset(mesh->supportSection, p, &off);
149: for (s = off; s < off+dof; ++s) {
150: PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);
151: }
152: }
153: PetscViewerFlush(viewer);
154: PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
155: for (p = pStart; p < pEnd; ++p) {
156: PetscInt dof, off, c;
158: PetscSectionGetDof(mesh->coneSection, p, &dof);
159: PetscSectionGetOffset(mesh->coneSection, p, &off);
160: for (c = off; c < off+dof; ++c) {
161: PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
162: }
163: }
164: PetscViewerFlush(viewer);
165: PetscSectionGetChart(coordSection, &pStart, NULL);
166: if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
167: DMPlexGetLabel(dm, "marker", &markers);
168: DMLabelView(markers,viewer);
169: if (size > 1) {
170: PetscSF sf;
172: DMGetPointSF(dm, &sf);
173: PetscSFView(sf, viewer);
174: }
175: PetscViewerFlush(viewer);
176: } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177: const char *name;
178: const char *colors[3] = {"red", "blue", "green"};
179: const int numColors = 3;
180: PetscReal scale = 2.0;
181: PetscScalar *coords;
182: PetscInt depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183: PetscMPIInt rank, size;
185: DMPlexGetDepth(dm, &depth);
186: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
187: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
188: PetscObjectGetName((PetscObject) dm, &name);
189: PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);
190: PetscViewerASCIIPrintf(viewer, "\
191: \\documentclass[crop,multi=false]{standalone}\n\n\
192: \\usepackage{tikz}\n\
193: \\usepackage{pgflibraryshapes}\n\
194: \\usetikzlibrary{backgrounds}\n\
195: \\usetikzlibrary{arrows}\n\
196: \\begin{document}\n\
197: \\section{%s}\n\
198: \\begin{center}\n", name, 8.0/scale);
199: PetscViewerASCIIPrintf(viewer, "Mesh for process ");
200: for (p = 0; p < size; ++p) {
201: if (p > 0 && p == size-1) {
202: PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
203: } else if (p > 0) {
204: PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
205: }
206: PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
207: }
208: PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209: \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");
210: /* Plot vertices */
211: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
212: VecGetArray(coordinates, &coords);
213: PetscViewerASCIIPrintf(viewer, "\\path\n");
214: for (v = vStart; v < vEnd; ++v) {
215: PetscInt off, dof, d;
217: PetscSectionGetDof(coordSection, v, &dof);
218: PetscSectionGetOffset(coordSection, v, &off);
219: PetscViewerASCIISynchronizedPrintf(viewer, "(");
220: for (d = 0; d < dof; ++d) {
221: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
222: PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)(scale*PetscRealPart(coords[off+d])));
223: }
224: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);
225: }
226: VecRestoreArray(coordinates, &coords);
227: PetscViewerFlush(viewer);
228: PetscViewerASCIIPrintf(viewer, "(0,0);\n");
229: /* Plot edges */
230: VecGetArray(coordinates, &coords);
231: PetscViewerASCIIPrintf(viewer, "\\path\n");
232: if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
233: for (e = eStart; e < eEnd; ++e) {
234: const PetscInt *cone;
235: PetscInt coneSize, offA, offB, dof, d;
237: DMPlexGetConeSize(dm, e, &coneSize);
238: if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239: DMPlexGetCone(dm, e, &cone);
240: PetscSectionGetDof(coordSection, cone[0], &dof);
241: PetscSectionGetOffset(coordSection, cone[0], &offA);
242: PetscSectionGetOffset(coordSection, cone[1], &offB);
243: PetscViewerASCIISynchronizedPrintf(viewer, "(");
244: for (d = 0; d < dof; ++d) {
245: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
246: PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)(scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d])));
247: }
248: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);
249: }
250: VecRestoreArray(coordinates, &coords);
251: PetscViewerFlush(viewer);
252: PetscViewerASCIIPrintf(viewer, "(0,0);\n");
253: /* Plot cells */
254: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
255: for (c = cStart; c < cEnd; ++c) {
256: PetscInt *closure = NULL;
257: PetscInt closureSize, firstPoint = -1;
259: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
260: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
261: for (p = 0; p < closureSize*2; p += 2) {
262: const PetscInt point = closure[p];
264: if ((point < vStart) || (point >= vEnd)) continue;
265: if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
266: PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);
267: if (firstPoint < 0) firstPoint = point;
268: }
269: /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
270: PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);
271: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
272: }
273: PetscViewerFlush(viewer);
274: PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");
275: PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
276: } else {
277: MPI_Comm comm;
278: PetscInt *sizes, *hybsizes;
279: PetscInt locDepth, depth, dim, d, pMax[4];
280: PetscInt pStart, pEnd, p;
281: PetscInt numLabels, l;
282: const char *name;
283: PetscMPIInt size;
285: PetscObjectGetComm((PetscObject)dm,&comm);
286: MPI_Comm_size(comm, &size);
287: DMPlexGetDimension(dm, &dim);
288: PetscObjectGetName((PetscObject) dm, &name);
289: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);}
290: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);}
291: DMPlexGetDepth(dm, &locDepth);
292: MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
293: DMPlexGetHybridBounds(dm, &pMax[depth], &pMax[depth-1], &pMax[1], &pMax[0]);
294: PetscMalloc2(size,&sizes,size,&hybsizes);
295: if (depth == 1) {
296: DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
297: pEnd = pEnd - pStart;
298: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
299: PetscViewerASCIIPrintf(viewer, " %D-cells:", 0);
300: for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
301: PetscViewerASCIIPrintf(viewer, "\n");
302: DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
303: pEnd = pEnd - pStart;
304: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
305: PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);
306: for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
307: PetscViewerASCIIPrintf(viewer, "\n");
308: } else {
309: for (d = 0; d <= dim; d++) {
310: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
311: pEnd -= pStart;
312: pMax[d] -= pStart;
313: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
314: MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
315: PetscViewerASCIIPrintf(viewer, " %D-cells:", d);
316: for (p = 0; p < size; ++p) {
317: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
318: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
319: }
320: PetscViewerASCIIPrintf(viewer, "\n");
321: }
322: }
323: PetscFree2(sizes,hybsizes);
324: DMPlexGetNumLabels(dm, &numLabels);
325: if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
326: for (l = 0; l < numLabels; ++l) {
327: DMLabel label;
328: const char *name;
329: IS valueIS;
330: const PetscInt *values;
331: PetscInt numValues, v;
333: DMPlexGetLabelName(dm, l, &name);
334: DMPlexGetLabel(dm, name, &label);
335: DMLabelGetNumValues(label, &numValues);
336: PetscViewerASCIIPrintf(viewer, " %s: %d strata of sizes (", name, numValues);
337: DMLabelGetValueIS(label, &valueIS);
338: ISGetIndices(valueIS, &values);
339: for (v = 0; v < numValues; ++v) {
340: PetscInt size;
342: DMLabelGetStratumSize(label, values[v], &size);
343: if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
344: PetscViewerASCIIPrintf(viewer, "%d", size);
345: }
346: PetscViewerASCIIPrintf(viewer, ")\n");
347: ISRestoreIndices(valueIS, &values);
348: ISDestroy(&valueIS);
349: }
350: }
351: return(0);
352: }
356: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
357: {
358: PetscBool iascii, isbinary;
364: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
365: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
366: if (iascii) {
367: DMPlexView_Ascii(dm, viewer);
368: #if 0
369: } else if (isbinary) {
370: DMPlexView_Binary(dm, viewer);
371: #endif
372: }
373: return(0);
374: }
378: PetscErrorCode DMDestroy_Plex(DM dm)
379: {
380: DM_Plex *mesh = (DM_Plex*) dm->data;
381: DMLabel next = mesh->labels;
385: if (--mesh->refct > 0) return(0);
386: PetscSectionDestroy(&mesh->coneSection);
387: PetscFree(mesh->cones);
388: PetscFree(mesh->coneOrientations);
389: PetscSectionDestroy(&mesh->supportSection);
390: PetscFree(mesh->supports);
391: PetscFree(mesh->facesTmp);
392: while (next) {
393: DMLabel tmp = next->next;
395: DMLabelDestroy(&next);
396: next = tmp;
397: }
398: DMLabelDestroy(&mesh->subpointMap);
399: ISDestroy(&mesh->globalVertexNumbers);
400: ISDestroy(&mesh->globalCellNumbers);
401: /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
402: PetscFree(mesh);
403: return(0);
404: }
408: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
409: {
410: PetscSection section, sectionGlobal;
411: PetscInt bs = -1;
412: PetscInt localSize;
413: PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock;
415: MatType mtype;
418: MatInitializePackage();
419: mtype = dm->mattype;
420: DMGetDefaultSection(dm, §ion);
421: DMGetDefaultGlobalSection(dm, §ionGlobal);
422: /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
423: PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
424: MatCreate(PetscObjectComm((PetscObject)dm), J);
425: MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
426: MatSetType(*J, mtype);
427: MatSetFromOptions(*J);
428: PetscStrcmp(mtype, MATSHELL, &isShell);
429: PetscStrcmp(mtype, MATBAIJ, &isBlock);
430: PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
431: PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
432: PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
433: PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
434: PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
435: if (!isShell) {
436: PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
437: PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
439: if (bs < 0) {
440: if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
441: PetscInt pStart, pEnd, p, dof, cdof;
443: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
444: for (p = pStart; p < pEnd; ++p) {
445: PetscSectionGetDof(sectionGlobal, p, &dof);
446: PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
447: if (dof-cdof) {
448: if (bs < 0) {
449: bs = dof-cdof;
450: } else if (bs != dof-cdof) {
451: /* Layout does not admit a pointwise block size */
452: bs = 1;
453: break;
454: }
455: }
456: }
457: /* Must have same blocksize on all procs (some might have no points) */
458: bsLocal = bs;
459: MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
460: bsLocal = bs < 0 ? bsMax : bs;
461: MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
462: if (bsMin != bsMax) {
463: bs = 1;
464: } else {
465: bs = bsMax;
466: }
467: } else {
468: bs = 1;
469: }
470: }
471: PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
472: DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);
473: PetscFree4(dnz, onz, dnzu, onzu);
474: }
475: return(0);
476: }
480: /*@
481: DMPlexGetDimension - Return the topological mesh dimension
483: Not collective
485: Input Parameter:
486: . mesh - The DMPlex
488: Output Parameter:
489: . dim - The topological mesh dimension
491: Level: beginner
493: .seealso: DMPlexCreate()
494: @*/
495: PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
496: {
497: DM_Plex *mesh = (DM_Plex*) dm->data;
502: *dim = mesh->dim;
503: return(0);
504: }
508: /*@
509: DMPlexSetDimension - Set the topological mesh dimension
511: Collective on mesh
513: Input Parameters:
514: + mesh - The DMPlex
515: - dim - The topological mesh dimension
517: Level: beginner
519: .seealso: DMPlexCreate()
520: @*/
521: PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
522: {
523: DM_Plex *mesh = (DM_Plex*) dm->data;
528: mesh->dim = dim;
529: mesh->preallocCenterDim = dim;
530: return(0);
531: }
535: /*@
536: DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
538: Not collective
540: Input Parameter:
541: . mesh - The DMPlex
543: Output Parameters:
544: + pStart - The first mesh point
545: - pEnd - The upper bound for mesh points
547: Level: beginner
549: .seealso: DMPlexCreate(), DMPlexSetChart()
550: @*/
551: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
552: {
553: DM_Plex *mesh = (DM_Plex*) dm->data;
558: PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
559: return(0);
560: }
564: /*@
565: DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
567: Not collective
569: Input Parameters:
570: + mesh - The DMPlex
571: . pStart - The first mesh point
572: - pEnd - The upper bound for mesh points
574: Output Parameters:
576: Level: beginner
578: .seealso: DMPlexCreate(), DMPlexGetChart()
579: @*/
580: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
581: {
582: DM_Plex *mesh = (DM_Plex*) dm->data;
587: PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
588: PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
589: return(0);
590: }
594: /*@
595: DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
597: Not collective
599: Input Parameters:
600: + mesh - The DMPlex
601: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
603: Output Parameter:
604: . size - The cone size for point p
606: Level: beginner
608: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
609: @*/
610: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
611: {
612: DM_Plex *mesh = (DM_Plex*) dm->data;
618: PetscSectionGetDof(mesh->coneSection, p, size);
619: return(0);
620: }
624: /*@
625: DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
627: Not collective
629: Input Parameters:
630: + mesh - The DMPlex
631: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
632: - size - The cone size for point p
634: Output Parameter:
636: Note:
637: This should be called after DMPlexSetChart().
639: Level: beginner
641: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
642: @*/
643: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
644: {
645: DM_Plex *mesh = (DM_Plex*) dm->data;
650: PetscSectionSetDof(mesh->coneSection, p, size);
652: mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
653: return(0);
654: }
658: /*@C
659: DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
661: Not collective
663: Input Parameters:
664: + mesh - The DMPlex
665: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
667: Output Parameter:
668: . cone - An array of points which are on the in-edges for point p
670: Level: beginner
672: Fortran Notes:
673: Since it returns an array, this routine is only available in Fortran 90, and you must
674: include petsc.h90 in your code.
676: You must also call DMPlexRestoreCone() after you finish using the returned array.
678: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
679: @*/
680: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
681: {
682: DM_Plex *mesh = (DM_Plex*) dm->data;
683: PetscInt off;
689: PetscSectionGetOffset(mesh->coneSection, p, &off);
690: *cone = &mesh->cones[off];
691: return(0);
692: }
696: /*@
697: DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
699: Not collective
701: Input Parameters:
702: + mesh - The DMPlex
703: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
704: - cone - An array of points which are on the in-edges for point p
706: Output Parameter:
708: Note:
709: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
711: Level: beginner
713: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
714: @*/
715: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
716: {
717: DM_Plex *mesh = (DM_Plex*) dm->data;
718: PetscInt pStart, pEnd;
719: PetscInt dof, off, c;
724: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
725: PetscSectionGetDof(mesh->coneSection, p, &dof);
727: PetscSectionGetOffset(mesh->coneSection, p, &off);
728: if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
729: for (c = 0; c < dof; ++c) {
730: if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
731: mesh->cones[off+c] = cone[c];
732: }
733: return(0);
734: }
738: /*@C
739: DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
741: Not collective
743: Input Parameters:
744: + mesh - The DMPlex
745: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
747: Output Parameter:
748: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
749: integer giving the prescription for cone traversal. If it is negative, the cone is
750: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
751: the index of the cone point on which to start.
753: Level: beginner
755: Fortran Notes:
756: Since it returns an array, this routine is only available in Fortran 90, and you must
757: include petsc.h90 in your code.
759: You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
761: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
762: @*/
763: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
764: {
765: DM_Plex *mesh = (DM_Plex*) dm->data;
766: PetscInt off;
771: #if defined(PETSC_USE_DEBUG)
772: {
773: PetscInt dof;
774: PetscSectionGetDof(mesh->coneSection, p, &dof);
776: }
777: #endif
778: PetscSectionGetOffset(mesh->coneSection, p, &off);
780: *coneOrientation = &mesh->coneOrientations[off];
781: return(0);
782: }
786: /*@
787: DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
789: Not collective
791: Input Parameters:
792: + mesh - The DMPlex
793: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
794: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
795: integer giving the prescription for cone traversal. If it is negative, the cone is
796: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
797: the index of the cone point on which to start.
799: Output Parameter:
801: Note:
802: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
804: Level: beginner
806: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
807: @*/
808: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
809: {
810: DM_Plex *mesh = (DM_Plex*) dm->data;
811: PetscInt pStart, pEnd;
812: PetscInt dof, off, c;
817: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
818: PetscSectionGetDof(mesh->coneSection, p, &dof);
820: PetscSectionGetOffset(mesh->coneSection, p, &off);
821: if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
822: for (c = 0; c < dof; ++c) {
823: PetscInt cdof, o = coneOrientation[c];
825: PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
826: if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
827: mesh->coneOrientations[off+c] = o;
828: }
829: return(0);
830: }
834: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
835: {
836: DM_Plex *mesh = (DM_Plex*) dm->data;
837: PetscInt pStart, pEnd;
838: PetscInt dof, off;
843: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
844: if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
845: if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
846: PetscSectionGetDof(mesh->coneSection, p, &dof);
847: PetscSectionGetOffset(mesh->coneSection, p, &off);
848: if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
849: mesh->cones[off+conePos] = conePoint;
850: return(0);
851: }
855: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
856: {
857: DM_Plex *mesh = (DM_Plex*) dm->data;
858: PetscInt pStart, pEnd;
859: PetscInt dof, off;
864: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
865: if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
866: PetscSectionGetDof(mesh->coneSection, p, &dof);
867: PetscSectionGetOffset(mesh->coneSection, p, &off);
868: if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
869: mesh->coneOrientations[off+conePos] = coneOrientation;
870: return(0);
871: }
875: /*@
876: DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
878: Not collective
880: Input Parameters:
881: + mesh - The DMPlex
882: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
884: Output Parameter:
885: . size - The support size for point p
887: Level: beginner
889: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
890: @*/
891: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
892: {
893: DM_Plex *mesh = (DM_Plex*) dm->data;
899: PetscSectionGetDof(mesh->supportSection, p, size);
900: return(0);
901: }
905: /*@
906: DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
908: Not collective
910: Input Parameters:
911: + mesh - The DMPlex
912: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
913: - size - The support size for point p
915: Output Parameter:
917: Note:
918: This should be called after DMPlexSetChart().
920: Level: beginner
922: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
923: @*/
924: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
925: {
926: DM_Plex *mesh = (DM_Plex*) dm->data;
931: PetscSectionSetDof(mesh->supportSection, p, size);
933: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
934: return(0);
935: }
939: /*@C
940: DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
942: Not collective
944: Input Parameters:
945: + mesh - The DMPlex
946: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
948: Output Parameter:
949: . support - An array of points which are on the out-edges for point p
951: Level: beginner
953: Fortran Notes:
954: Since it returns an array, this routine is only available in Fortran 90, and you must
955: include petsc.h90 in your code.
957: You must also call DMPlexRestoreSupport() after you finish using the returned array.
959: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
960: @*/
961: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
962: {
963: DM_Plex *mesh = (DM_Plex*) dm->data;
964: PetscInt off;
970: PetscSectionGetOffset(mesh->supportSection, p, &off);
971: *support = &mesh->supports[off];
972: return(0);
973: }
977: /*@
978: DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
980: Not collective
982: Input Parameters:
983: + mesh - The DMPlex
984: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
985: - support - An array of points which are on the in-edges for point p
987: Output Parameter:
989: Note:
990: This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
992: Level: beginner
994: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
995: @*/
996: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
997: {
998: DM_Plex *mesh = (DM_Plex*) dm->data;
999: PetscInt pStart, pEnd;
1000: PetscInt dof, off, c;
1005: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1006: PetscSectionGetDof(mesh->supportSection, p, &dof);
1008: PetscSectionGetOffset(mesh->supportSection, p, &off);
1009: if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1010: for (c = 0; c < dof; ++c) {
1011: if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1012: mesh->supports[off+c] = support[c];
1013: }
1014: return(0);
1015: }
1019: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1020: {
1021: DM_Plex *mesh = (DM_Plex*) dm->data;
1022: PetscInt pStart, pEnd;
1023: PetscInt dof, off;
1028: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1029: PetscSectionGetDof(mesh->supportSection, p, &dof);
1030: PetscSectionGetOffset(mesh->supportSection, p, &off);
1031: if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1032: if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1033: if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1034: mesh->supports[off+supportPos] = supportPoint;
1035: return(0);
1036: }
1040: /*@C
1041: DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1043: Not collective
1045: Input Parameters:
1046: + mesh - The DMPlex
1047: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1048: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
1049: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1051: Output Parameters:
1052: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1053: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1055: Note:
1056: If using internal storage (points is NULL on input), each call overwrites the last output.
1058: Fortran Notes:
1059: Since it returns an array, this routine is only available in Fortran 90, and you must
1060: include petsc.h90 in your code.
1062: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1064: Level: beginner
1066: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1067: @*/
1068: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1069: {
1070: DM_Plex *mesh = (DM_Plex*) dm->data;
1071: PetscInt *closure, *fifo;
1072: const PetscInt *tmp = NULL, *tmpO = NULL;
1073: PetscInt tmpSize, t;
1074: PetscInt depth = 0, maxSize;
1075: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
1076: PetscErrorCode ierr;
1080: DMPlexGetDepth(dm, &depth);
1081: /* This is only 1-level */
1082: if (useCone) {
1083: DMPlexGetConeSize(dm, p, &tmpSize);
1084: DMPlexGetCone(dm, p, &tmp);
1085: DMPlexGetConeOrientation(dm, p, &tmpO);
1086: } else {
1087: DMPlexGetSupportSize(dm, p, &tmpSize);
1088: DMPlexGetSupport(dm, p, &tmp);
1089: }
1090: if (depth == 1) {
1091: if (*points) {
1092: closure = *points;
1093: } else {
1094: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1095: DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1096: }
1097: closure[0] = p; closure[1] = 0;
1098: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1099: closure[closureSize] = tmp[t];
1100: closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1101: }
1102: if (numPoints) *numPoints = closureSize/2;
1103: if (points) *points = closure;
1104: return(0);
1105: }
1106: maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1107: DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1108: if (*points) {
1109: closure = *points;
1110: } else {
1111: DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1112: }
1113: closure[0] = p; closure[1] = 0;
1114: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1115: const PetscInt cp = tmp[t];
1116: const PetscInt co = tmpO ? tmpO[t] : 0;
1118: closure[closureSize] = cp;
1119: closure[closureSize+1] = co;
1120: fifo[fifoSize] = cp;
1121: fifo[fifoSize+1] = co;
1122: }
1123: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1124: while (fifoSize - fifoStart) {
1125: const PetscInt q = fifo[fifoStart];
1126: const PetscInt o = fifo[fifoStart+1];
1127: const PetscInt rev = o >= 0 ? 0 : 1;
1128: const PetscInt off = rev ? -(o+1) : o;
1130: if (useCone) {
1131: DMPlexGetConeSize(dm, q, &tmpSize);
1132: DMPlexGetCone(dm, q, &tmp);
1133: DMPlexGetConeOrientation(dm, q, &tmpO);
1134: } else {
1135: DMPlexGetSupportSize(dm, q, &tmpSize);
1136: DMPlexGetSupport(dm, q, &tmp);
1137: tmpO = NULL;
1138: }
1139: for (t = 0; t < tmpSize; ++t) {
1140: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
1141: const PetscInt cp = tmp[i];
1142: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1143: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1144: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1145: PetscInt co = tmpO ? tmpO[i] : 0;
1146: PetscInt c;
1148: if (rev) {
1149: PetscInt childSize, coff;
1150: DMPlexGetConeSize(dm, cp, &childSize);
1151: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1152: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1153: }
1154: /* Check for duplicate */
1155: for (c = 0; c < closureSize; c += 2) {
1156: if (closure[c] == cp) break;
1157: }
1158: if (c == closureSize) {
1159: closure[closureSize] = cp;
1160: closure[closureSize+1] = co;
1161: fifo[fifoSize] = cp;
1162: fifo[fifoSize+1] = co;
1163: closureSize += 2;
1164: fifoSize += 2;
1165: }
1166: }
1167: fifoStart += 2;
1168: }
1169: if (numPoints) *numPoints = closureSize/2;
1170: if (points) *points = closure;
1171: DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1172: return(0);
1173: }
1177: /*@C
1178: DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG with a specified initial orientation
1180: Not collective
1182: Input Parameters:
1183: + mesh - The DMPlex
1184: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1185: . orientation - The orientation of the point
1186: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
1187: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1189: Output Parameters:
1190: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1191: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1193: Note:
1194: If using internal storage (points is NULL on input), each call overwrites the last output.
1196: Fortran Notes:
1197: Since it returns an array, this routine is only available in Fortran 90, and you must
1198: include petsc.h90 in your code.
1200: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1202: Level: beginner
1204: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1205: @*/
1206: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1207: {
1208: DM_Plex *mesh = (DM_Plex*) dm->data;
1209: PetscInt *closure, *fifo;
1210: const PetscInt *tmp = NULL, *tmpO = NULL;
1211: PetscInt tmpSize, t;
1212: PetscInt depth = 0, maxSize;
1213: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
1214: PetscErrorCode ierr;
1218: DMPlexGetDepth(dm, &depth);
1219: /* This is only 1-level */
1220: if (useCone) {
1221: DMPlexGetConeSize(dm, p, &tmpSize);
1222: DMPlexGetCone(dm, p, &tmp);
1223: DMPlexGetConeOrientation(dm, p, &tmpO);
1224: } else {
1225: DMPlexGetSupportSize(dm, p, &tmpSize);
1226: DMPlexGetSupport(dm, p, &tmp);
1227: }
1228: if (depth == 1) {
1229: if (*points) {
1230: closure = *points;
1231: } else {
1232: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1233: DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1234: }
1235: closure[0] = p; closure[1] = ornt;
1236: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1237: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1238: closure[closureSize] = tmp[i];
1239: closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1240: }
1241: if (numPoints) *numPoints = closureSize/2;
1242: if (points) *points = closure;
1243: return(0);
1244: }
1245: maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1246: DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1247: if (*points) {
1248: closure = *points;
1249: } else {
1250: DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1251: }
1252: closure[0] = p; closure[1] = ornt;
1253: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1254: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1255: const PetscInt cp = tmp[i];
1256: PetscInt co = tmpO ? tmpO[i] : 0;
1258: if (ornt < 0) {
1259: PetscInt childSize, coff;
1260: DMPlexGetConeSize(dm, cp, &childSize);
1261: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1262: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1263: }
1264: closure[closureSize] = cp;
1265: closure[closureSize+1] = co;
1266: fifo[fifoSize] = cp;
1267: fifo[fifoSize+1] = co;
1268: }
1269: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1270: while (fifoSize - fifoStart) {
1271: const PetscInt q = fifo[fifoStart];
1272: const PetscInt o = fifo[fifoStart+1];
1273: const PetscInt rev = o >= 0 ? 0 : 1;
1274: const PetscInt off = rev ? -(o+1) : o;
1276: if (useCone) {
1277: DMPlexGetConeSize(dm, q, &tmpSize);
1278: DMPlexGetCone(dm, q, &tmp);
1279: DMPlexGetConeOrientation(dm, q, &tmpO);
1280: } else {
1281: DMPlexGetSupportSize(dm, q, &tmpSize);
1282: DMPlexGetSupport(dm, q, &tmp);
1283: tmpO = NULL;
1284: }
1285: for (t = 0; t < tmpSize; ++t) {
1286: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
1287: const PetscInt cp = tmp[i];
1288: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1289: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1290: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1291: PetscInt co = tmpO ? tmpO[i] : 0;
1292: PetscInt c;
1294: if (rev) {
1295: PetscInt childSize, coff;
1296: DMPlexGetConeSize(dm, cp, &childSize);
1297: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1298: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1299: }
1300: /* Check for duplicate */
1301: for (c = 0; c < closureSize; c += 2) {
1302: if (closure[c] == cp) break;
1303: }
1304: if (c == closureSize) {
1305: closure[closureSize] = cp;
1306: closure[closureSize+1] = co;
1307: fifo[fifoSize] = cp;
1308: fifo[fifoSize+1] = co;
1309: closureSize += 2;
1310: fifoSize += 2;
1311: }
1312: }
1313: fifoStart += 2;
1314: }
1315: if (numPoints) *numPoints = closureSize/2;
1316: if (points) *points = closure;
1317: DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1318: return(0);
1319: }
1323: /*@C
1324: DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1326: Not collective
1328: Input Parameters:
1329: + mesh - The DMPlex
1330: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1331: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
1332: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
1333: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
1335: Note:
1336: If not using internal storage (points is not NULL on input), this call is unnecessary
1338: Fortran Notes:
1339: Since it returns an array, this routine is only available in Fortran 90, and you must
1340: include petsc.h90 in your code.
1342: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1344: Level: beginner
1346: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1347: @*/
1348: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1349: {
1356: DMRestoreWorkArray(dm, 0, PETSC_INT, points);
1357: if (numPoints) *numPoints = 0;
1358: return(0);
1359: }
1363: /*@
1364: DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1366: Not collective
1368: Input Parameter:
1369: . mesh - The DMPlex
1371: Output Parameters:
1372: + maxConeSize - The maximum number of in-edges
1373: - maxSupportSize - The maximum number of out-edges
1375: Level: beginner
1377: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1378: @*/
1379: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1380: {
1381: DM_Plex *mesh = (DM_Plex*) dm->data;
1385: if (maxConeSize) *maxConeSize = mesh->maxConeSize;
1386: if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1387: return(0);
1388: }
1392: PetscErrorCode DMSetUp_Plex(DM dm)
1393: {
1394: DM_Plex *mesh = (DM_Plex*) dm->data;
1395: PetscInt size;
1400: PetscSectionSetUp(mesh->coneSection);
1401: PetscSectionGetStorageSize(mesh->coneSection, &size);
1402: PetscMalloc1(size, &mesh->cones);
1403: PetscCalloc1(size, &mesh->coneOrientations);
1404: if (mesh->maxSupportSize) {
1405: PetscSectionSetUp(mesh->supportSection);
1406: PetscSectionGetStorageSize(mesh->supportSection, &size);
1407: PetscMalloc1(size, &mesh->supports);
1408: }
1409: return(0);
1410: }
1414: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1415: {
1419: if (subdm) {DMClone(dm, subdm);}
1420: DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
1421: return(0);
1422: }
1426: /*@
1427: DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1429: Not collective
1431: Input Parameter:
1432: . mesh - The DMPlex
1434: Output Parameter:
1436: Note:
1437: This should be called after all calls to DMPlexSetCone()
1439: Level: beginner
1441: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1442: @*/
1443: PetscErrorCode DMPlexSymmetrize(DM dm)
1444: {
1445: DM_Plex *mesh = (DM_Plex*) dm->data;
1446: PetscInt *offsets;
1447: PetscInt supportSize;
1448: PetscInt pStart, pEnd, p;
1453: if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1454: /* Calculate support sizes */
1455: DMPlexGetChart(dm, &pStart, &pEnd);
1456: for (p = pStart; p < pEnd; ++p) {
1457: PetscInt dof, off, c;
1459: PetscSectionGetDof(mesh->coneSection, p, &dof);
1460: PetscSectionGetOffset(mesh->coneSection, p, &off);
1461: for (c = off; c < off+dof; ++c) {
1462: PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
1463: }
1464: }
1465: for (p = pStart; p < pEnd; ++p) {
1466: PetscInt dof;
1468: PetscSectionGetDof(mesh->supportSection, p, &dof);
1470: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1471: }
1472: PetscSectionSetUp(mesh->supportSection);
1473: /* Calculate supports */
1474: PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
1475: PetscMalloc1(supportSize, &mesh->supports);
1476: PetscCalloc1(pEnd - pStart, &offsets);
1477: for (p = pStart; p < pEnd; ++p) {
1478: PetscInt dof, off, c;
1480: PetscSectionGetDof(mesh->coneSection, p, &dof);
1481: PetscSectionGetOffset(mesh->coneSection, p, &off);
1482: for (c = off; c < off+dof; ++c) {
1483: const PetscInt q = mesh->cones[c];
1484: PetscInt offS;
1486: PetscSectionGetOffset(mesh->supportSection, q, &offS);
1488: mesh->supports[offS+offsets[q]] = p;
1489: ++offsets[q];
1490: }
1491: }
1492: PetscFree(offsets);
1493: return(0);
1494: }
1498: /*@
1499: DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1500: can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1501: same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1502: the DAG.
1504: Not collective
1506: Input Parameter:
1507: . mesh - The DMPlex
1509: Output Parameter:
1511: Notes:
1512: The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1513: have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1515: This should be called after all calls to DMPlexSymmetrize()
1517: Level: beginner
1519: .seealso: DMPlexCreate(), DMPlexSymmetrize()
1520: @*/
1521: PetscErrorCode DMPlexStratify(DM dm)
1522: {
1523: DMLabel label;
1524: PetscInt pStart, pEnd, p;
1525: PetscInt numRoots = 0, numLeaves = 0;
1530: PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
1531: /* Calculate depth */
1532: DMPlexGetChart(dm, &pStart, &pEnd);
1533: DMPlexCreateLabel(dm, "depth");
1534: DMPlexGetDepthLabel(dm, &label);
1535: /* Initialize roots and count leaves */
1536: for (p = pStart; p < pEnd; ++p) {
1537: PetscInt coneSize, supportSize;
1539: DMPlexGetConeSize(dm, p, &coneSize);
1540: DMPlexGetSupportSize(dm, p, &supportSize);
1541: if (!coneSize && supportSize) {
1542: ++numRoots;
1543: DMLabelSetValue(label, p, 0);
1544: } else if (!supportSize && coneSize) {
1545: ++numLeaves;
1546: } else if (!supportSize && !coneSize) {
1547: /* Isolated points */
1548: DMLabelSetValue(label, p, 0);
1549: }
1550: }
1551: if (numRoots + numLeaves == (pEnd - pStart)) {
1552: for (p = pStart; p < pEnd; ++p) {
1553: PetscInt coneSize, supportSize;
1555: DMPlexGetConeSize(dm, p, &coneSize);
1556: DMPlexGetSupportSize(dm, p, &supportSize);
1557: if (!supportSize && coneSize) {
1558: DMLabelSetValue(label, p, 1);
1559: }
1560: }
1561: } else {
1562: IS pointIS;
1563: PetscInt numPoints = 0, level = 0;
1565: DMLabelGetStratumIS(label, level, &pointIS);
1566: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
1567: while (numPoints) {
1568: const PetscInt *points;
1569: const PetscInt newLevel = level+1;
1571: ISGetIndices(pointIS, &points);
1572: for (p = 0; p < numPoints; ++p) {
1573: const PetscInt point = points[p];
1574: const PetscInt *support;
1575: PetscInt supportSize, s;
1577: DMPlexGetSupportSize(dm, point, &supportSize);
1578: DMPlexGetSupport(dm, point, &support);
1579: for (s = 0; s < supportSize; ++s) {
1580: DMLabelSetValue(label, support[s], newLevel);
1581: }
1582: }
1583: ISRestoreIndices(pointIS, &points);
1584: ++level;
1585: ISDestroy(&pointIS);
1586: DMLabelGetStratumIS(label, level, &pointIS);
1587: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
1588: else {numPoints = 0;}
1589: }
1590: ISDestroy(&pointIS);
1591: }
1592: PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
1593: return(0);
1594: }
1598: /*@C
1599: DMPlexGetJoin - Get an array for the join of the set of points
1601: Not Collective
1603: Input Parameters:
1604: + dm - The DMPlex object
1605: . numPoints - The number of input points for the join
1606: - points - The input points
1608: Output Parameters:
1609: + numCoveredPoints - The number of points in the join
1610: - coveredPoints - The points in the join
1612: Level: intermediate
1614: Note: Currently, this is restricted to a single level join
1616: Fortran Notes:
1617: Since it returns an array, this routine is only available in Fortran 90, and you must
1618: include petsc.h90 in your code.
1620: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1622: .keywords: mesh
1623: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1624: @*/
1625: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1626: {
1627: DM_Plex *mesh = (DM_Plex*) dm->data;
1628: PetscInt *join[2];
1629: PetscInt joinSize, i = 0;
1630: PetscInt dof, off, p, c, m;
1638: DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
1639: DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
1640: /* Copy in support of first point */
1641: PetscSectionGetDof(mesh->supportSection, points[0], &dof);
1642: PetscSectionGetOffset(mesh->supportSection, points[0], &off);
1643: for (joinSize = 0; joinSize < dof; ++joinSize) {
1644: join[i][joinSize] = mesh->supports[off+joinSize];
1645: }
1646: /* Check each successive support */
1647: for (p = 1; p < numPoints; ++p) {
1648: PetscInt newJoinSize = 0;
1650: PetscSectionGetDof(mesh->supportSection, points[p], &dof);
1651: PetscSectionGetOffset(mesh->supportSection, points[p], &off);
1652: for (c = 0; c < dof; ++c) {
1653: const PetscInt point = mesh->supports[off+c];
1655: for (m = 0; m < joinSize; ++m) {
1656: if (point == join[i][m]) {
1657: join[1-i][newJoinSize++] = point;
1658: break;
1659: }
1660: }
1661: }
1662: joinSize = newJoinSize;
1663: i = 1-i;
1664: }
1665: *numCoveredPoints = joinSize;
1666: *coveredPoints = join[i];
1667: DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
1668: return(0);
1669: }
1673: /*@C
1674: DMPlexRestoreJoin - Restore an array for the join of the set of points
1676: Not Collective
1678: Input Parameters:
1679: + dm - The DMPlex object
1680: . numPoints - The number of input points for the join
1681: - points - The input points
1683: Output Parameters:
1684: + numCoveredPoints - The number of points in the join
1685: - coveredPoints - The points in the join
1687: Fortran Notes:
1688: Since it returns an array, this routine is only available in Fortran 90, and you must
1689: include petsc.h90 in your code.
1691: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1693: Level: intermediate
1695: .keywords: mesh
1696: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1697: @*/
1698: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1699: {
1707: DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
1708: if (numCoveredPoints) *numCoveredPoints = 0;
1709: return(0);
1710: }
1714: /*@C
1715: DMPlexGetFullJoin - Get an array for the join of the set of points
1717: Not Collective
1719: Input Parameters:
1720: + dm - The DMPlex object
1721: . numPoints - The number of input points for the join
1722: - points - The input points
1724: Output Parameters:
1725: + numCoveredPoints - The number of points in the join
1726: - coveredPoints - The points in the join
1728: Fortran Notes:
1729: Since it returns an array, this routine is only available in Fortran 90, and you must
1730: include petsc.h90 in your code.
1732: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1734: Level: intermediate
1736: .keywords: mesh
1737: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1738: @*/
1739: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1740: {
1741: DM_Plex *mesh = (DM_Plex*) dm->data;
1742: PetscInt *offsets, **closures;
1743: PetscInt *join[2];
1744: PetscInt depth = 0, maxSize, joinSize = 0, i = 0;
1745: PetscInt p, d, c, m;
1754: DMPlexGetDepth(dm, &depth);
1755: PetscCalloc1(numPoints, &closures);
1756: DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
1757: maxSize = PetscPowInt(mesh->maxSupportSize,depth+1);
1758: DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
1759: DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);
1761: for (p = 0; p < numPoints; ++p) {
1762: PetscInt closureSize;
1764: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);
1766: offsets[p*(depth+2)+0] = 0;
1767: for (d = 0; d < depth+1; ++d) {
1768: PetscInt pStart, pEnd, i;
1770: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
1771: for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1772: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1773: offsets[p*(depth+2)+d+1] = i;
1774: break;
1775: }
1776: }
1777: if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1778: }
1779: if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
1780: }
1781: for (d = 0; d < depth+1; ++d) {
1782: PetscInt dof;
1784: /* Copy in support of first point */
1785: dof = offsets[d+1] - offsets[d];
1786: for (joinSize = 0; joinSize < dof; ++joinSize) {
1787: join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1788: }
1789: /* Check each successive cone */
1790: for (p = 1; p < numPoints && joinSize; ++p) {
1791: PetscInt newJoinSize = 0;
1793: dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
1794: for (c = 0; c < dof; ++c) {
1795: const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
1797: for (m = 0; m < joinSize; ++m) {
1798: if (point == join[i][m]) {
1799: join[1-i][newJoinSize++] = point;
1800: break;
1801: }
1802: }
1803: }
1804: joinSize = newJoinSize;
1805: i = 1-i;
1806: }
1807: if (joinSize) break;
1808: }
1809: *numCoveredPoints = joinSize;
1810: *coveredPoints = join[i];
1811: for (p = 0; p < numPoints; ++p) {
1812: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
1813: }
1814: PetscFree(closures);
1815: DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
1816: DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
1817: return(0);
1818: }
1822: /*@C
1823: DMPlexGetMeet - Get an array for the meet of the set of points
1825: Not Collective
1827: Input Parameters:
1828: + dm - The DMPlex object
1829: . numPoints - The number of input points for the meet
1830: - points - The input points
1832: Output Parameters:
1833: + numCoveredPoints - The number of points in the meet
1834: - coveredPoints - The points in the meet
1836: Level: intermediate
1838: Note: Currently, this is restricted to a single level meet
1840: Fortran Notes:
1841: Since it returns an array, this routine is only available in Fortran 90, and you must
1842: include petsc.h90 in your code.
1844: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1846: .keywords: mesh
1847: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1848: @*/
1849: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1850: {
1851: DM_Plex *mesh = (DM_Plex*) dm->data;
1852: PetscInt *meet[2];
1853: PetscInt meetSize, i = 0;
1854: PetscInt dof, off, p, c, m;
1862: DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
1863: DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
1864: /* Copy in cone of first point */
1865: PetscSectionGetDof(mesh->coneSection, points[0], &dof);
1866: PetscSectionGetOffset(mesh->coneSection, points[0], &off);
1867: for (meetSize = 0; meetSize < dof; ++meetSize) {
1868: meet[i][meetSize] = mesh->cones[off+meetSize];
1869: }
1870: /* Check each successive cone */
1871: for (p = 1; p < numPoints; ++p) {
1872: PetscInt newMeetSize = 0;
1874: PetscSectionGetDof(mesh->coneSection, points[p], &dof);
1875: PetscSectionGetOffset(mesh->coneSection, points[p], &off);
1876: for (c = 0; c < dof; ++c) {
1877: const PetscInt point = mesh->cones[off+c];
1879: for (m = 0; m < meetSize; ++m) {
1880: if (point == meet[i][m]) {
1881: meet[1-i][newMeetSize++] = point;
1882: break;
1883: }
1884: }
1885: }
1886: meetSize = newMeetSize;
1887: i = 1-i;
1888: }
1889: *numCoveringPoints = meetSize;
1890: *coveringPoints = meet[i];
1891: DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
1892: return(0);
1893: }
1897: /*@C
1898: DMPlexRestoreMeet - Restore an array for the meet of the set of points
1900: Not Collective
1902: Input Parameters:
1903: + dm - The DMPlex object
1904: . numPoints - The number of input points for the meet
1905: - points - The input points
1907: Output Parameters:
1908: + numCoveredPoints - The number of points in the meet
1909: - coveredPoints - The points in the meet
1911: Level: intermediate
1913: Fortran Notes:
1914: Since it returns an array, this routine is only available in Fortran 90, and you must
1915: include petsc.h90 in your code.
1917: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1919: .keywords: mesh
1920: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
1921: @*/
1922: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1923: {
1931: DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
1932: if (numCoveredPoints) *numCoveredPoints = 0;
1933: return(0);
1934: }
1938: /*@C
1939: DMPlexGetFullMeet - Get an array for the meet of the set of points
1941: Not Collective
1943: Input Parameters:
1944: + dm - The DMPlex object
1945: . numPoints - The number of input points for the meet
1946: - points - The input points
1948: Output Parameters:
1949: + numCoveredPoints - The number of points in the meet
1950: - coveredPoints - The points in the meet
1952: Level: intermediate
1954: Fortran Notes:
1955: Since it returns an array, this routine is only available in Fortran 90, and you must
1956: include petsc.h90 in your code.
1958: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1960: .keywords: mesh
1961: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
1962: @*/
1963: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1964: {
1965: DM_Plex *mesh = (DM_Plex*) dm->data;
1966: PetscInt *offsets, **closures;
1967: PetscInt *meet[2];
1968: PetscInt height = 0, maxSize, meetSize = 0, i = 0;
1969: PetscInt p, h, c, m;
1978: DMPlexGetDepth(dm, &height);
1979: PetscMalloc1(numPoints, &closures);
1980: DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
1981: maxSize = PetscPowInt(mesh->maxConeSize,height+1);
1982: DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
1983: DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);
1985: for (p = 0; p < numPoints; ++p) {
1986: PetscInt closureSize;
1988: DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);
1990: offsets[p*(height+2)+0] = 0;
1991: for (h = 0; h < height+1; ++h) {
1992: PetscInt pStart, pEnd, i;
1994: DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
1995: for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
1996: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1997: offsets[p*(height+2)+h+1] = i;
1998: break;
1999: }
2000: }
2001: if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2002: }
2003: if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2004: }
2005: for (h = 0; h < height+1; ++h) {
2006: PetscInt dof;
2008: /* Copy in cone of first point */
2009: dof = offsets[h+1] - offsets[h];
2010: for (meetSize = 0; meetSize < dof; ++meetSize) {
2011: meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2012: }
2013: /* Check each successive cone */
2014: for (p = 1; p < numPoints && meetSize; ++p) {
2015: PetscInt newMeetSize = 0;
2017: dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2018: for (c = 0; c < dof; ++c) {
2019: const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2021: for (m = 0; m < meetSize; ++m) {
2022: if (point == meet[i][m]) {
2023: meet[1-i][newMeetSize++] = point;
2024: break;
2025: }
2026: }
2027: }
2028: meetSize = newMeetSize;
2029: i = 1-i;
2030: }
2031: if (meetSize) break;
2032: }
2033: *numCoveredPoints = meetSize;
2034: *coveredPoints = meet[i];
2035: for (p = 0; p < numPoints; ++p) {
2036: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2037: }
2038: PetscFree(closures);
2039: DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2040: DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2041: return(0);
2042: }
2046: /*@C
2047: DMPlexEqual - Determine if two DMs have the same topology
2049: Not Collective
2051: Input Parameters:
2052: + dmA - A DMPlex object
2053: - dmB - A DMPlex object
2055: Output Parameters:
2056: . equal - PETSC_TRUE if the topologies are identical
2058: Level: intermediate
2060: Notes:
2061: We are not solving graph isomorphism, so we do not permutation.
2063: .keywords: mesh
2064: .seealso: DMPlexGetCone()
2065: @*/
2066: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2067: {
2068: PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
2076: *equal = PETSC_FALSE;
2077: DMPlexGetDepth(dmA, &depth);
2078: DMPlexGetDepth(dmB, &depthB);
2079: if (depth != depthB) return(0);
2080: DMPlexGetChart(dmA, &pStart, &pEnd);
2081: DMPlexGetChart(dmB, &pStartB, &pEndB);
2082: if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2083: for (p = pStart; p < pEnd; ++p) {
2084: const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2085: PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s;
2087: DMPlexGetConeSize(dmA, p, &coneSize);
2088: DMPlexGetCone(dmA, p, &cone);
2089: DMPlexGetConeOrientation(dmA, p, &ornt);
2090: DMPlexGetConeSize(dmB, p, &coneSizeB);
2091: DMPlexGetCone(dmB, p, &coneB);
2092: DMPlexGetConeOrientation(dmB, p, &orntB);
2093: if (coneSize != coneSizeB) return(0);
2094: for (c = 0; c < coneSize; ++c) {
2095: if (cone[c] != coneB[c]) return(0);
2096: if (ornt[c] != orntB[c]) return(0);
2097: }
2098: DMPlexGetSupportSize(dmA, p, &supportSize);
2099: DMPlexGetSupport(dmA, p, &support);
2100: DMPlexGetSupportSize(dmB, p, &supportSizeB);
2101: DMPlexGetSupport(dmB, p, &supportB);
2102: if (supportSize != supportSizeB) return(0);
2103: for (s = 0; s < supportSize; ++s) {
2104: if (support[s] != supportB[s]) return(0);
2105: }
2106: }
2107: *equal = PETSC_TRUE;
2108: return(0);
2109: }
2113: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2114: {
2115: MPI_Comm comm;
2119: PetscObjectGetComm((PetscObject)dm,&comm);
2121: switch (cellDim) {
2122: case 0:
2123: *numFaceVertices = 0;
2124: break;
2125: case 1:
2126: *numFaceVertices = 1;
2127: break;
2128: case 2:
2129: switch (numCorners) {
2130: case 3: /* triangle */
2131: *numFaceVertices = 2; /* Edge has 2 vertices */
2132: break;
2133: case 4: /* quadrilateral */
2134: *numFaceVertices = 2; /* Edge has 2 vertices */
2135: break;
2136: case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2137: *numFaceVertices = 3; /* Edge has 3 vertices */
2138: break;
2139: case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2140: *numFaceVertices = 3; /* Edge has 3 vertices */
2141: break;
2142: default:
2143: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2144: }
2145: break;
2146: case 3:
2147: switch (numCorners) {
2148: case 4: /* tetradehdron */
2149: *numFaceVertices = 3; /* Face has 3 vertices */
2150: break;
2151: case 6: /* tet cohesive cells */
2152: *numFaceVertices = 4; /* Face has 4 vertices */
2153: break;
2154: case 8: /* hexahedron */
2155: *numFaceVertices = 4; /* Face has 4 vertices */
2156: break;
2157: case 9: /* tet cohesive Lagrange cells */
2158: *numFaceVertices = 6; /* Face has 6 vertices */
2159: break;
2160: case 10: /* quadratic tetrahedron */
2161: *numFaceVertices = 6; /* Face has 6 vertices */
2162: break;
2163: case 12: /* hex cohesive Lagrange cells */
2164: *numFaceVertices = 6; /* Face has 6 vertices */
2165: break;
2166: case 18: /* quadratic tet cohesive Lagrange cells */
2167: *numFaceVertices = 6; /* Face has 6 vertices */
2168: break;
2169: case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2170: *numFaceVertices = 9; /* Face has 9 vertices */
2171: break;
2172: default:
2173: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2174: }
2175: break;
2176: default:
2177: SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2178: }
2179: return(0);
2180: }
2184: /* Trys to give the mesh a consistent orientation */
2185: PetscErrorCode DMPlexOrient(DM dm)
2186: {
2187: PetscBT seenCells, flippedCells, seenFaces;
2188: PetscInt *faceFIFO, fTop, fBottom;
2189: PetscInt dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO;
2193: /* Truth Table
2194: mismatch flips do action mismatch flipA ^ flipB action
2195: F 0 flips no F F F
2196: F 1 flip yes F T T
2197: F 2 flips no T F T
2198: T 0 flips yes T T F
2199: T 1 flip no
2200: T 2 flips yes
2201: */
2202: DMPlexGetDimension(dm, &dim);
2203: DMPlexGetVTKCellHeight(dm, &h);
2204: DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
2205: DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);
2206: PetscBTCreate(cEnd - cStart, &seenCells);
2207: PetscBTMemzero(cEnd - cStart, seenCells);
2208: PetscBTCreate(cEnd - cStart, &flippedCells);
2209: PetscBTMemzero(cEnd - cStart, flippedCells);
2210: PetscBTCreate(fEnd - fStart, &seenFaces);
2211: PetscBTMemzero(fEnd - fStart, seenFaces);
2212: PetscMalloc1((fEnd - fStart), &faceFIFO);
2213: fTop = fBottom = 0;
2214: /* Initialize FIFO with first cell */
2215: if (cEnd > cStart) {
2216: const PetscInt *cone;
2217: PetscInt coneSize;
2219: DMPlexGetConeSize(dm, cStart, &coneSize);
2220: DMPlexGetCone(dm, cStart, &cone);
2221: for (c = 0; c < coneSize; ++c) {
2222: faceFIFO[fBottom++] = cone[c];
2223: PetscBTSet(seenFaces, cone[c]-fStart);
2224: }
2225: }
2226: /* Consider each face in FIFO */
2227: while (fTop < fBottom) {
2228: const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
2229: PetscInt supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
2230: PetscInt seenA, flippedA, seenB, flippedB, mismatch;
2232: face = faceFIFO[fTop++];
2233: DMPlexGetSupportSize(dm, face, &supportSize);
2234: DMPlexGetSupport(dm, face, &support);
2235: if (supportSize < 2) continue;
2236: if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
2237: seenA = PetscBTLookup(seenCells, support[0]-cStart);
2238: flippedA = PetscBTLookup(flippedCells, support[0]-cStart) ? 1 : 0;
2239: seenB = PetscBTLookup(seenCells, support[1]-cStart);
2240: flippedB = PetscBTLookup(flippedCells, support[1]-cStart) ? 1 : 0;
2242: DMPlexGetConeSize(dm, support[0], &coneSizeA);
2243: DMPlexGetConeSize(dm, support[1], &coneSizeB);
2244: DMPlexGetCone(dm, support[0], &coneA);
2245: DMPlexGetCone(dm, support[1], &coneB);
2246: DMPlexGetConeOrientation(dm, support[0], &coneOA);
2247: DMPlexGetConeOrientation(dm, support[1], &coneOB);
2248: for (c = 0; c < coneSizeA; ++c) {
2249: if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
2250: faceFIFO[fBottom++] = coneA[c];
2251: PetscBTSet(seenFaces, coneA[c]-fStart);
2252: }
2253: if (coneA[c] == face) posA = c;
2254: if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2255: }
2256: if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
2257: for (c = 0; c < coneSizeB; ++c) {
2258: if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
2259: faceFIFO[fBottom++] = coneB[c];
2260: PetscBTSet(seenFaces, coneB[c]-fStart);
2261: }
2262: if (coneB[c] == face) posB = c;
2263: if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2264: }
2265: if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);
2267: if (dim == 1) {
2268: mismatch = posA == posB;
2269: } else {
2270: mismatch = coneOA[posA] == coneOB[posB];
2271: }
2273: if (mismatch ^ (flippedA ^ flippedB)) {
2274: if (seenA && seenB) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %d and %d do not match: Fault mesh is non-orientable", support[0], support[1]);
2275: if (!seenA && !flippedA) {
2276: PetscBTSet(flippedCells, support[0]-cStart);
2277: } else if (!seenB && !flippedB) {
2278: PetscBTSet(flippedCells, support[1]-cStart);
2279: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2280: } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2281: PetscBTSet(seenCells, support[0]-cStart);
2282: PetscBTSet(seenCells, support[1]-cStart);
2283: }
2285: DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
2286: DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);
2287: DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);
2288: for (c = cStart; c < cEnd; ++c) {
2289: const PetscInt *cone, *coneO, *support;
2290: PetscInt coneSize, supportSize, faceSize, cp, sp;
2292: if (!PetscBTLookup(flippedCells, c-cStart)) continue;
2293: DMPlexGetConeSize(dm, c, &coneSize);
2294: DMPlexGetCone(dm, c, &cone);
2295: DMPlexGetConeOrientation(dm, c, &coneO);
2296: for (cp = 0; cp < coneSize; ++cp) {
2297: const PetscInt rcp = coneSize-cp-1;
2299: DMPlexGetConeSize(dm, cone[rcp], &faceSize);
2300: revcone[cp] = cone[rcp];
2301: revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp];
2302: }
2303: DMPlexSetCone(dm, c, revcone);
2304: DMPlexSetConeOrientation(dm, c, revconeO);
2305: /* Reverse orientations of support */
2306: faceSize = coneSize;
2307: DMPlexGetSupportSize(dm, c, &supportSize);
2308: DMPlexGetSupport(dm, c, &support);
2309: for (sp = 0; sp < supportSize; ++sp) {
2310: DMPlexGetConeSize(dm, support[sp], &coneSize);
2311: DMPlexGetCone(dm, support[sp], &cone);
2312: DMPlexGetConeOrientation(dm, support[sp], &coneO);
2313: for (cp = 0; cp < coneSize; ++cp) {
2314: if (cone[cp] != c) continue;
2315: DMPlexInsertConeOrientation(dm, support[sp], cp, coneO[cp] >= 0 ? -(faceSize-coneO[cp]) : faceSize+coneO[cp]);
2316: }
2317: }
2318: }
2319: DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);
2320: DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);
2321: PetscBTDestroy(&seenCells);
2322: PetscBTDestroy(&flippedCells);
2323: PetscBTDestroy(&seenFaces);
2324: PetscFree(faceFIFO);
2325: return(0);
2326: }
2330: static PetscErrorCode DMPlexGetAdjacencySingleLevel_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
2331: {
2332: const PetscInt *support = NULL;
2333: PetscInt numAdj = 0, maxAdjSize = *adjSize, supportSize, s;
2334: PetscErrorCode ierr;
2337: if (useClosure) {
2338: DMPlexGetConeSize(dm, p, &supportSize);
2339: DMPlexGetCone(dm, p, &support);
2340: for (s = 0; s < supportSize; ++s) {
2341: const PetscInt *cone = NULL;
2342: PetscInt coneSize, c, q;
2344: DMPlexGetSupportSize(dm, support[s], &coneSize);
2345: DMPlexGetSupport(dm, support[s], &cone);
2346: for (c = 0; c < coneSize; ++c) {
2347: for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2348: if (cone[c] == adj[q]) break;
2349: }
2350: if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2351: }
2352: }
2353: } else {
2354: DMPlexGetSupportSize(dm, p, &supportSize);
2355: DMPlexGetSupport(dm, p, &support);
2356: for (s = 0; s < supportSize; ++s) {
2357: const PetscInt *cone = NULL;
2358: PetscInt coneSize, c, q;
2360: DMPlexGetConeSize(dm, support[s], &coneSize);
2361: DMPlexGetCone(dm, support[s], &cone);
2362: for (c = 0; c < coneSize; ++c) {
2363: for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2364: if (cone[c] == adj[q]) break;
2365: }
2366: if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2367: }
2368: }
2369: }
2370: *adjSize = numAdj;
2371: return(0);
2372: }
2376: PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2377: {
2378: const PetscInt maxFaceCases = 30;
2379: PetscInt numFaceCases = 0;
2380: PetscInt numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2381: PetscInt *off, *adj;
2382: PetscInt *neighborCells, *tmpClosure;
2383: PetscInt maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2384: PetscInt dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2388: /* For parallel partitioning, I think you have to communicate supports */
2389: DMPlexGetDimension(dm, &dim);
2390: cellDim = dim - cellHeight;
2391: DMPlexGetDepth(dm, &depth);
2392: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
2393: DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
2394: if (cEnd - cStart == 0) {
2395: if (numVertices) *numVertices = 0;
2396: if (offsets) *offsets = NULL;
2397: if (adjacency) *adjacency = NULL;
2398: return(0);
2399: }
2400: numCells = cEnd - cStart;
2401: faceDepth = depth - cellHeight;
2402: if (dim == depth) {
2403: PetscInt f, fStart, fEnd;
2405: PetscCalloc1(numCells+1, &off);
2406: /* Count neighboring cells */
2407: DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);
2408: for (f = fStart; f < fEnd; ++f) {
2409: const PetscInt *support;
2410: PetscInt supportSize;
2411: DMPlexGetSupportSize(dm, f, &supportSize);
2412: DMPlexGetSupport(dm, f, &support);
2413: if (supportSize == 2) {
2414: ++off[support[0]-cStart+1];
2415: ++off[support[1]-cStart+1];
2416: }
2417: }
2418: /* Prefix sum */
2419: for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
2420: if (adjacency) {
2421: PetscInt *tmp;
2423: PetscMalloc1(off[numCells], &adj);
2424: PetscMalloc1((numCells+1), &tmp);
2425: PetscMemcpy(tmp, off, (numCells+1) * sizeof(PetscInt));
2426: /* Get neighboring cells */
2427: for (f = fStart; f < fEnd; ++f) {
2428: const PetscInt *support;
2429: PetscInt supportSize;
2430: DMPlexGetSupportSize(dm, f, &supportSize);
2431: DMPlexGetSupport(dm, f, &support);
2432: if (supportSize == 2) {
2433: adj[tmp[support[0]-cStart]++] = support[1];
2434: adj[tmp[support[1]-cStart]++] = support[0];
2435: }
2436: }
2437: #if defined(PETSC_USE_DEBUG)
2438: for (c = 0; c < cEnd-cStart; ++c) if (tmp[c] != off[c+1]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Offset %d != %d for cell %d", tmp[c], off[c], c+cStart);
2439: #endif
2440: PetscFree(tmp);
2441: }
2442: if (numVertices) *numVertices = numCells;
2443: if (offsets) *offsets = off;
2444: if (adjacency) *adjacency = adj;
2445: return(0);
2446: }
2447: /* Setup face recognition */
2448: if (faceDepth == 1) {
2449: PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
2451: for (c = cStart; c < cEnd; ++c) {
2452: PetscInt corners;
2454: DMPlexGetConeSize(dm, c, &corners);
2455: if (!cornersSeen[corners]) {
2456: PetscInt nFV;
2458: if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2459: cornersSeen[corners] = 1;
2461: DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);
2463: numFaceVertices[numFaceCases++] = nFV;
2464: }
2465: }
2466: }
2467: maxClosure = 2*PetscMax(PetscPowInt(maxConeSize,depth+1),PetscPowInt(maxSupportSize,depth+1));
2468: maxNeighbors = PetscPowInt(maxConeSize,depth+1)*PetscPowInt(maxSupportSize,depth+1);
2469: PetscMalloc2(maxNeighbors,&neighborCells,maxClosure,&tmpClosure);
2470: PetscCalloc1(numCells+1, &off);
2471: /* Count neighboring cells */
2472: for (cell = cStart; cell < cEnd; ++cell) {
2473: PetscInt numNeighbors = maxNeighbors, n;
2475: DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);
2476: /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2477: for (n = 0; n < numNeighbors; ++n) {
2478: PetscInt cellPair[2];
2479: PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2480: PetscInt meetSize = 0;
2481: const PetscInt *meet = NULL;
2483: cellPair[0] = cell; cellPair[1] = neighborCells[n];
2484: if (cellPair[0] == cellPair[1]) continue;
2485: if (!found) {
2486: DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);
2487: if (meetSize) {
2488: PetscInt f;
2490: for (f = 0; f < numFaceCases; ++f) {
2491: if (numFaceVertices[f] == meetSize) {
2492: found = PETSC_TRUE;
2493: break;
2494: }
2495: }
2496: }
2497: DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);
2498: }
2499: if (found) ++off[cell-cStart+1];
2500: }
2501: }
2502: /* Prefix sum */
2503: for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2505: if (adjacency) {
2506: PetscMalloc1(off[numCells], &adj);
2507: /* Get neighboring cells */
2508: for (cell = cStart; cell < cEnd; ++cell) {
2509: PetscInt numNeighbors = maxNeighbors, n;
2510: PetscInt cellOffset = 0;
2512: DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);
2513: /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2514: for (n = 0; n < numNeighbors; ++n) {
2515: PetscInt cellPair[2];
2516: PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2517: PetscInt meetSize = 0;
2518: const PetscInt *meet = NULL;
2520: cellPair[0] = cell; cellPair[1] = neighborCells[n];
2521: if (cellPair[0] == cellPair[1]) continue;
2522: if (!found) {
2523: DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);
2524: if (meetSize) {
2525: PetscInt f;
2527: for (f = 0; f < numFaceCases; ++f) {
2528: if (numFaceVertices[f] == meetSize) {
2529: found = PETSC_TRUE;
2530: break;
2531: }
2532: }
2533: }
2534: DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);
2535: }
2536: if (found) {
2537: adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2538: ++cellOffset;
2539: }
2540: }
2541: }
2542: }
2543: PetscFree2(neighborCells,tmpClosure);
2544: if (numVertices) *numVertices = numCells;
2545: if (offsets) *offsets = off;
2546: if (adjacency) *adjacency = adj;
2547: return(0);
2548: }
2550: #if defined(PETSC_HAVE_CHACO)
2551: #if defined(PETSC_HAVE_UNISTD_H)
2552: #include <unistd.h>
2553: #endif
2554: /* Chaco does not have an include file */
2555: PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2556: float *ewgts, float *x, float *y, float *z, char *outassignname,
2557: char *outfilename, short *assignment, int architecture, int ndims_tot,
2558: int mesh_dims[3], double *goal, int global_method, int local_method,
2559: int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2561: extern int FREE_GRAPH;
2565: PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2566: {
2567: enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2568: MPI_Comm comm;
2569: int nvtxs = numVertices; /* number of vertices in full graph */
2570: int *vwgts = NULL; /* weights for all vertices */
2571: float *ewgts = NULL; /* weights for all edges */
2572: float *x = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2573: char *outassignname = NULL; /* name of assignment output file */
2574: char *outfilename = NULL; /* output file name */
2575: int architecture = 1; /* 0 => hypercube, d => d-dimensional mesh */
2576: int ndims_tot = 0; /* total number of cube dimensions to divide */
2577: int mesh_dims[3]; /* dimensions of mesh of processors */
2578: double *goal = NULL; /* desired set sizes for each set */
2579: int global_method = 1; /* global partitioning algorithm */
2580: int local_method = 1; /* local partitioning algorithm */
2581: int rqi_flag = 0; /* should I use RQI/Symmlq eigensolver? */
2582: int vmax = 200; /* how many vertices to coarsen down to? */
2583: int ndims = 1; /* number of eigenvectors (2^d sets) */
2584: double eigtol = 0.001; /* tolerance on eigenvectors */
2585: long seed = 123636512; /* for random graph mutations */
2586: short int *assignment; /* Output partition */
2587: int fd_stdout, fd_pipe[2];
2588: PetscInt *points;
2589: PetscMPIInt commSize;
2590: int i, v, p;
2594: PetscObjectGetComm((PetscObject)dm,&comm);
2595: MPI_Comm_size(comm, &commSize);
2596: if (!numVertices) {
2597: PetscSectionCreate(comm, partSection);
2598: PetscSectionSetChart(*partSection, 0, commSize);
2599: PetscSectionSetUp(*partSection);
2600: ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);
2601: return(0);
2602: }
2603: FREE_GRAPH = 0; /* Do not let Chaco free my memory */
2604: for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2606: if (global_method == INERTIAL_METHOD) {
2607: /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2608: SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2609: }
2610: mesh_dims[0] = commSize;
2611: mesh_dims[1] = 1;
2612: mesh_dims[2] = 1;
2613: PetscMalloc1(nvtxs, &assignment);
2614: /* Chaco outputs to stdout. We redirect this to a buffer. */
2615: /* TODO: check error codes for UNIX calls */
2616: #if defined(PETSC_HAVE_UNISTD_H)
2617: {
2618: int piperet;
2619: piperet = pipe(fd_pipe);
2620: if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2621: fd_stdout = dup(1);
2622: close(1);
2623: dup2(fd_pipe[1], 1);
2624: }
2625: #endif
2626: interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2627: assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2628: vmax, ndims, eigtol, seed);
2629: #if defined(PETSC_HAVE_UNISTD_H)
2630: {
2631: char msgLog[10000];
2632: int count;
2634: fflush(stdout);
2635: count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2636: if (count < 0) count = 0;
2637: msgLog[count] = 0;
2638: close(1);
2639: dup2(fd_stdout, 1);
2640: close(fd_stdout);
2641: close(fd_pipe[0]);
2642: close(fd_pipe[1]);
2643: if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2644: }
2645: #endif
2646: /* Convert to PetscSection+IS */
2647: PetscSectionCreate(comm, partSection);
2648: PetscSectionSetChart(*partSection, 0, commSize);
2649: for (v = 0; v < nvtxs; ++v) {
2650: PetscSectionAddDof(*partSection, assignment[v], 1);
2651: }
2652: PetscSectionSetUp(*partSection);
2653: PetscMalloc1(nvtxs, &points);
2654: for (p = 0, i = 0; p < commSize; ++p) {
2655: for (v = 0; v < nvtxs; ++v) {
2656: if (assignment[v] == p) points[i++] = v;
2657: }
2658: }
2659: if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2660: ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);
2661: if (global_method == INERTIAL_METHOD) {
2662: /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2663: }
2664: PetscFree(assignment);
2665: for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2666: return(0);
2667: }
2668: #endif
2670: #if defined(PETSC_HAVE_PARMETIS)
2671: #include <parmetis.h>
2675: PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2676: {
2677: MPI_Comm comm;
2678: PetscInt nvtxs = numVertices; /* The number of vertices in full graph */
2679: PetscInt *vtxdist; /* Distribution of vertices across processes */
2680: PetscInt *xadj = start; /* Start of edge list for each vertex */
2681: PetscInt *adjncy = adjacency; /* Edge lists for all vertices */
2682: PetscInt *vwgt = NULL; /* Vertex weights */
2683: PetscInt *adjwgt = NULL; /* Edge weights */
2684: PetscInt wgtflag = 0; /* Indicates which weights are present */
2685: PetscInt numflag = 0; /* Indicates initial offset (0 or 1) */
2686: PetscInt ncon = 1; /* The number of weights per vertex */
2687: PetscInt nparts; /* The number of partitions */
2688: PetscReal *tpwgts; /* The fraction of vertex weights assigned to each partition */
2689: PetscReal *ubvec; /* The balance intolerance for vertex weights */
2690: PetscInt options[5]; /* Options */
2691: /* Outputs */
2692: PetscInt edgeCut; /* The number of edges cut by the partition */
2693: PetscInt *assignment, *points;
2694: PetscMPIInt commSize, rank, p, v, i;
2698: PetscObjectGetComm((PetscObject) dm, &comm);
2699: MPI_Comm_size(comm, &commSize);
2700: MPI_Comm_rank(comm, &rank);
2701: nparts = commSize;
2702: options[0] = 0; /* Use all defaults */
2703: /* Calculate vertex distribution */
2704: PetscMalloc4(nparts+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment);
2705: vtxdist[0] = 0;
2706: MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);
2707: for (p = 2; p <= nparts; ++p) {
2708: vtxdist[p] += vtxdist[p-1];
2709: }
2710: /* Calculate weights */
2711: for (p = 0; p < nparts; ++p) {
2712: tpwgts[p] = 1.0/nparts;
2713: }
2714: ubvec[0] = 1.05;
2716: if (nparts == 1) {
2717: PetscMemzero(assignment, nvtxs * sizeof(PetscInt));
2718: } else {
2719: if (vtxdist[1] == vtxdist[nparts]) {
2720: if (!rank) {
2721: PetscStackPush("METIS_PartGraphKway");
2722: METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment);
2723: PetscStackPop;
2724: if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
2725: }
2726: } else {
2727: PetscStackPush("ParMETIS_V3_PartKway");
2728: ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm);
2729: PetscStackPop;
2730: if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
2731: }
2732: }
2733: /* Convert to PetscSection+IS */
2734: PetscSectionCreate(comm, partSection);
2735: PetscSectionSetChart(*partSection, 0, commSize);
2736: for (v = 0; v < nvtxs; ++v) {
2737: PetscSectionAddDof(*partSection, assignment[v], 1);
2738: }
2739: PetscSectionSetUp(*partSection);
2740: PetscMalloc1(nvtxs, &points);
2741: for (p = 0, i = 0; p < commSize; ++p) {
2742: for (v = 0; v < nvtxs; ++v) {
2743: if (assignment[v] == p) points[i++] = v;
2744: }
2745: }
2746: if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2747: ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);
2748: PetscFree4(vtxdist,tpwgts,ubvec,assignment);
2749: return(0);
2750: }
2751: #endif
2755: /* Expand the partition by BFS on the adjacency graph */
2756: PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2757: {
2758: PetscHashI h;
2759: const PetscInt *points;
2760: PetscInt **tmpPoints, *newPoints, totPoints = 0;
2761: PetscInt pStart, pEnd, part, q;
2762: PetscErrorCode ierr;
2765: PetscHashICreate(h);
2766: PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);
2767: PetscSectionGetChart(origPartSection, &pStart, &pEnd);
2768: PetscSectionSetChart(*partSection, pStart, pEnd);
2769: ISGetIndices(origPartition, &points);
2770: PetscMalloc1((pEnd - pStart), &tmpPoints);
2771: for (part = pStart; part < pEnd; ++part) {
2772: PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2774: PetscHashIClear(h);
2775: PetscSectionGetDof(origPartSection, part, &numPoints);
2776: PetscSectionGetOffset(origPartSection, part, &off);
2777: /* Add all existing points to h */
2778: for (p = 0; p < numPoints; ++p) {
2779: const PetscInt point = points[off+p];
2780: PetscHashIAdd(h, point, 1);
2781: }
2782: PetscHashISize(h, nP);
2783: if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2784: /* Add all points in next BFS level */
2785: /* TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2786: for (p = 0; p < numPoints; ++p) {
2787: const PetscInt point = points[off+p];
2788: PetscInt s = start[point], e = start[point+1], a;
2790: for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2791: }
2792: PetscHashISize(h, numNewPoints);
2793: PetscSectionSetDof(*partSection, part, numNewPoints);
2794: PetscMalloc1(numNewPoints, &tmpPoints[part]);
2795: PetscHashIGetKeys(h, &n, tmpPoints[part]);
2796: totPoints += numNewPoints;
2797: }
2798: ISRestoreIndices(origPartition, &points);
2799: PetscHashIDestroy(h);
2800: PetscSectionSetUp(*partSection);
2801: PetscMalloc1(totPoints, &newPoints);
2802: for (part = pStart, q = 0; part < pEnd; ++part) {
2803: PetscInt numPoints, p;
2805: PetscSectionGetDof(*partSection, part, &numPoints);
2806: for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2807: PetscFree(tmpPoints[part]);
2808: }
2809: PetscFree(tmpPoints);
2810: ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);
2811: return(0);
2812: }
2816: /*
2817: DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2819: Collective on DM
2821: Input Parameters:
2822: + dm - The DM
2823: . height - The height for points in the partition
2824: - enlarge - Expand each partition with neighbors
2826: Output Parameters:
2827: + partSection - The PetscSection giving the division of points by partition
2828: . partition - The list of points by partition
2829: . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2830: - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2832: Level: developer
2834: .seealso DMPlexDistribute()
2835: */
2836: PetscErrorCode DMPlexCreatePartition(DM dm, const char name[], PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2837: {
2838: char partname[1024];
2839: PetscBool isChaco = PETSC_FALSE, isMetis = PETSC_FALSE, flg;
2840: PetscMPIInt size;
2844: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
2846: *origPartSection = NULL;
2847: *origPartition = NULL;
2848: if (size == 1) {
2849: PetscInt *points;
2850: PetscInt cStart, cEnd, c;
2852: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
2853: PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);
2854: PetscSectionSetChart(*partSection, 0, size);
2855: PetscSectionSetDof(*partSection, 0, cEnd-cStart);
2856: PetscSectionSetUp(*partSection);
2857: PetscMalloc1((cEnd - cStart), &points);
2858: for (c = cStart; c < cEnd; ++c) points[c] = c;
2859: ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);
2860: return(0);
2861: }
2862: PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_partitioner", partname, 1024, &flg);
2863: if (flg) name = partname;
2864: if (name) {
2865: PetscStrcmp(name, "chaco", &isChaco);
2866: PetscStrcmp(name, "metis", &isMetis);
2867: }
2868: if (height == 0) {
2869: PetscInt numVertices;
2870: PetscInt *start = NULL;
2871: PetscInt *adjacency = NULL;
2873: DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);
2874: if (!name || isChaco) {
2875: #if defined(PETSC_HAVE_CHACO)
2876: DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);
2877: #else
2878: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
2879: #endif
2880: } else if (isMetis) {
2881: #if defined(PETSC_HAVE_PARMETIS)
2882: DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);
2883: #endif
2884: } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Unknown mesh partitioning package %s", name);
2885: if (enlarge) {
2886: *origPartSection = *partSection;
2887: *origPartition = *partition;
2889: DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);
2890: }
2891: PetscFree(start);
2892: PetscFree(adjacency);
2893: # if 0
2894: } else if (height == 1) {
2895: /* Build the dual graph for faces and partition the hypergraph */
2896: PetscInt numEdges;
2898: buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2899: GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2900: destroyCSR(numEdges, start, adjacency);
2901: #endif
2902: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2903: return(0);
2904: }
2908: PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2909: {
2910: /* const PetscInt height = 0; */
2911: const PetscInt *partArray;
2912: PetscInt *allPoints, *packPoints;
2913: PetscInt rStart, rEnd, rank, pStart, pEnd, newSize;
2914: PetscErrorCode ierr;
2915: PetscBT bt;
2916: PetscSegBuffer segpack,segpart;
2919: PetscSectionGetChart(pointSection, &rStart, &rEnd);
2920: ISGetIndices(pointPartition, &partArray);
2921: PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
2922: PetscSectionSetChart(*section, rStart, rEnd);
2923: DMPlexGetChart(dm,&pStart,&pEnd);
2924: PetscBTCreate(pEnd-pStart,&bt);
2925: PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);
2926: PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);
2927: for (rank = rStart; rank < rEnd; ++rank) {
2928: PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;
2930: PetscSectionGetDof(pointSection, rank, &numPoints);
2931: PetscSectionGetOffset(pointSection, rank, &offset);
2932: for (p = 0; p < numPoints; ++p) {
2933: PetscInt point = partArray[offset+p], closureSize, c;
2934: PetscInt *closure = NULL;
2936: /* TODO Include support for height > 0 case */
2937: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
2938: for (c=0; c<closureSize; c++) {
2939: PetscInt cpoint = closure[c*2];
2940: if (!PetscBTLookupSet(bt,cpoint-pStart)) {
2941: PetscInt *PETSC_RESTRICT pt;
2942: partSize++;
2943: PetscSegBufferGetInts(segpart,1,&pt);
2944: *pt = cpoint;
2945: }
2946: }
2947: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
2948: }
2949: PetscSectionSetDof(*section, rank, partSize);
2950: PetscSegBufferGetInts(segpack,partSize,&placePoints);
2951: PetscSegBufferExtractTo(segpart,placePoints);
2952: PetscSortInt(partSize,placePoints);
2953: for (p=0; p<partSize; p++) {PetscBTClear(bt,placePoints[p]-pStart);}
2954: }
2955: PetscBTDestroy(&bt);
2956: PetscSegBufferDestroy(&segpart);
2958: PetscSectionSetUp(*section);
2959: PetscSectionGetStorageSize(*section, &newSize);
2960: PetscMalloc1(newSize, &allPoints);
2962: PetscSegBufferExtractInPlace(segpack,&packPoints);
2963: for (rank = rStart; rank < rEnd; ++rank) {
2964: PetscInt numPoints, offset;
2966: PetscSectionGetDof(*section, rank, &numPoints);
2967: PetscSectionGetOffset(*section, rank, &offset);
2968: PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));
2969: packPoints += numPoints;
2970: }
2972: PetscSegBufferDestroy(&segpack);
2973: ISRestoreIndices(pointPartition, &partArray);
2974: ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);
2975: return(0);
2976: }
2980: /*@
2981: DMPlexDistributeField - Distribute field data to match a given PetscSF, usually the SF from mesh distribution
2983: Collective on DM
2985: Input Parameters:
2986: + dm - The DMPlex object
2987: . pointSF - The PetscSF describing the communication pattern
2988: . originalSection - The PetscSection for existing data layout
2989: - originalVec - The existing data
2991: Output Parameters:
2992: + newSection - The PetscSF describing the new data layout
2993: - newVec - The new data
2995: Level: developer
2997: .seealso: DMPlexDistribute(), DMPlexDistributeData()
2998: @*/
2999: PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3000: {
3001: PetscSF fieldSF;
3002: PetscInt *remoteOffsets, fieldSize;
3003: PetscScalar *originalValues, *newValues;
3007: PetscLogEventBegin(DMPLEX_DistributeField,dm,0,0,0);
3008: PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);
3010: PetscSectionGetStorageSize(newSection, &fieldSize);
3011: VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);
3012: VecSetType(newVec,dm->vectype);
3014: VecGetArray(originalVec, &originalValues);
3015: VecGetArray(newVec, &newValues);
3016: PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);
3017: PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);
3018: PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);
3019: PetscSFDestroy(&fieldSF);
3020: VecRestoreArray(newVec, &newValues);
3021: VecRestoreArray(originalVec, &originalValues);
3022: PetscLogEventEnd(DMPLEX_DistributeField,dm,0,0,0);
3023: return(0);
3024: }
3028: /*@
3029: DMPlexDistributeData - Distribute field data to match a given PetscSF, usually the SF from mesh distribution
3031: Collective on DM
3033: Input Parameters:
3034: + dm - The DMPlex object
3035: . pointSF - The PetscSF describing the communication pattern
3036: . originalSection - The PetscSection for existing data layout
3037: . datatype - The type of data
3038: - originalData - The existing data
3040: Output Parameters:
3041: + newSection - The PetscSF describing the new data layout
3042: - newData - The new data
3044: Level: developer
3046: .seealso: DMPlexDistribute(), DMPlexDistributeField()
3047: @*/
3048: PetscErrorCode DMPlexDistributeData(DM dm, PetscSF pointSF, PetscSection originalSection, MPI_Datatype datatype, void *originalData, PetscSection newSection, void **newData)
3049: {
3050: PetscSF fieldSF;
3051: PetscInt *remoteOffsets, fieldSize;
3052: PetscMPIInt dataSize;
3056: PetscLogEventBegin(DMPLEX_DistributeData,dm,0,0,0);
3057: PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);
3059: PetscSectionGetStorageSize(newSection, &fieldSize);
3060: MPI_Type_size(datatype, &dataSize);
3061: PetscMalloc(fieldSize * dataSize, newData);
3063: PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);
3064: PetscSFBcastBegin(fieldSF, datatype, originalData, *newData);
3065: PetscSFBcastEnd(fieldSF, datatype, originalData, *newData);
3066: PetscSFDestroy(&fieldSF);
3067: PetscLogEventEnd(DMPLEX_DistributeData,dm,0,0,0);
3068: return(0);
3069: }
3073: /*@C
3074: DMPlexDistribute - Distributes the mesh and any associated sections.
3076: Not Collective
3078: Input Parameter:
3079: + dm - The original DMPlex object
3080: . partitioner - The partitioning package, or NULL for the default
3081: - overlap - The overlap of partitions, 0 is the default
3083: Output Parameter:
3084: + sf - The PetscSF used for point distribution
3085: - parallelMesh - The distributed DMPlex object, or NULL
3087: Note: If the mesh was not distributed, the return value is NULL
3089: Level: intermediate
3091: .keywords: mesh, elements
3092: .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3093: @*/
3094: PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, PetscSF *sf, DM *dmParallel)
3095: {
3096: DM_Plex *mesh = (DM_Plex*) dm->data, *pmesh;
3097: MPI_Comm comm;
3098: const PetscInt height = 0;
3099: PetscInt dim, numRemoteRanks;
3100: IS origCellPart, origPart, cellPart, part;
3101: PetscSection origCellPartSection, origPartSection, cellPartSection, partSection;
3102: PetscSFNode *remoteRanks;
3103: PetscSF partSF, pointSF, coneSF;
3104: ISLocalToGlobalMapping renumbering;
3105: PetscSection originalConeSection, newConeSection;
3106: PetscInt *remoteOffsets;
3107: PetscInt *cones, *newCones, newConesSize;
3108: PetscBool flg;
3109: PetscMPIInt rank, numProcs, p;
3110: PetscErrorCode ierr;
3117: PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);
3118: PetscObjectGetComm((PetscObject)dm,&comm);
3119: MPI_Comm_rank(comm, &rank);
3120: MPI_Comm_size(comm, &numProcs);
3122: *dmParallel = NULL;
3123: if (numProcs == 1) return(0);
3125: DMPlexGetDimension(dm, &dim);
3126: /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3127: PetscLogEventBegin(DMPLEX_Partition,dm,0,0,0);
3128: if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3129: DMPlexCreatePartition(dm, partitioner, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);
3130: /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3131: if (!rank) numRemoteRanks = numProcs;
3132: else numRemoteRanks = 0;
3133: PetscMalloc1(numRemoteRanks, &remoteRanks);
3134: for (p = 0; p < numRemoteRanks; ++p) {
3135: remoteRanks[p].rank = p;
3136: remoteRanks[p].index = 0;
3137: }
3138: PetscSFCreate(comm, &partSF);
3139: PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);
3140: PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);
3141: if (flg) {
3142: PetscPrintf(comm, "Cell Partition:\n");
3143: PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);
3144: ISView(cellPart, NULL);
3145: if (origCellPart) {
3146: PetscPrintf(comm, "Original Cell Partition:\n");
3147: PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);
3148: ISView(origCellPart, NULL);
3149: }
3150: PetscSFView(partSF, NULL);
3151: }
3152: /* Close the partition over the mesh */
3153: DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);
3154: ISDestroy(&cellPart);
3155: PetscSectionDestroy(&cellPartSection);
3156: /* Create new mesh */
3157: DMPlexCreate(comm, dmParallel);
3158: DMPlexSetDimension(*dmParallel, dim);
3159: PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");
3160: pmesh = (DM_Plex*) (*dmParallel)->data;
3161: /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3162: PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);
3163: if (flg) {
3164: PetscPrintf(comm, "Point Partition:\n");
3165: PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);
3166: ISView(part, NULL);
3167: PetscSFView(pointSF, NULL);
3168: PetscPrintf(comm, "Point Renumbering after partition:\n");
3169: ISLocalToGlobalMappingView(renumbering, NULL);
3170: }
3171: PetscLogEventEnd(DMPLEX_Partition,dm,0,0,0);
3172: PetscLogEventBegin(DMPLEX_DistributeCones,dm,0,0,0);
3173: /* Distribute cone section */
3174: DMPlexGetConeSection(dm, &originalConeSection);
3175: DMPlexGetConeSection(*dmParallel, &newConeSection);
3176: PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);
3177: DMSetUp(*dmParallel);
3178: {
3179: PetscInt pStart, pEnd, p;
3181: PetscSectionGetChart(newConeSection, &pStart, &pEnd);
3182: for (p = pStart; p < pEnd; ++p) {
3183: PetscInt coneSize;
3184: PetscSectionGetDof(newConeSection, p, &coneSize);
3185: pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3186: }
3187: }
3188: /* Communicate and renumber cones */
3189: PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);
3190: DMPlexGetCones(dm, &cones);
3191: DMPlexGetCones(*dmParallel, &newCones);
3192: PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);
3193: PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);
3194: PetscSectionGetStorageSize(newConeSection, &newConesSize);
3195: ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);
3196: PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);
3197: if (flg) {
3198: PetscPrintf(comm, "Serial Cone Section:\n");
3199: PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);
3200: PetscPrintf(comm, "Parallel Cone Section:\n");
3201: PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);
3202: PetscSFView(coneSF, NULL);
3203: }
3204: DMPlexGetConeOrientations(dm, &cones);
3205: DMPlexGetConeOrientations(*dmParallel, &newCones);
3206: PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);
3207: PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);
3208: PetscSFDestroy(&coneSF);
3209: PetscLogEventEnd(DMPLEX_DistributeCones,dm,0,0,0);
3210: /* Create supports and stratify sieve */
3211: {
3212: PetscInt pStart, pEnd;
3214: PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);
3215: PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);
3216: }
3217: DMPlexSymmetrize(*dmParallel);
3218: DMPlexStratify(*dmParallel);
3219: /* Distribute Coordinates */
3220: {
3221: PetscSection originalCoordSection, newCoordSection;
3222: Vec originalCoordinates, newCoordinates;
3223: const char *name;
3225: DMGetCoordinateSection(dm, &originalCoordSection);
3226: DMGetCoordinateSection(*dmParallel, &newCoordSection);
3227: DMGetCoordinatesLocal(dm, &originalCoordinates);
3228: VecCreate(comm, &newCoordinates);
3229: PetscObjectGetName((PetscObject) originalCoordinates, &name);
3230: PetscObjectSetName((PetscObject) newCoordinates, name);
3232: DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);
3233: DMSetCoordinatesLocal(*dmParallel, newCoordinates);
3234: VecDestroy(&newCoordinates);
3235: }
3236: /* Distribute labels */
3237: PetscLogEventBegin(DMPLEX_DistributeLabels,dm,0,0,0);
3238: {
3239: DMLabel next = mesh->labels, newNext = pmesh->labels;
3240: PetscInt numLabels = 0, l;
3242: /* Bcast number of labels */
3243: while (next) {++numLabels; next = next->next;}
3244: MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);
3245: next = mesh->labels;
3246: for (l = 0; l < numLabels; ++l) {
3247: DMLabel labelNew;
3248: PetscBool isdepth;
3250: /* Skip "depth" because it is recreated */
3251: if (!rank) {PetscStrcmp(next->name, "depth", &isdepth);}
3252: MPI_Bcast(&isdepth, 1, MPIU_BOOL, 0, comm);
3253: if (isdepth) {if (!rank) next = next->next; continue;}
3254: DMLabelDistribute(next, partSection, part, renumbering, &labelNew);
3255: /* Insert into list */
3256: if (newNext) newNext->next = labelNew;
3257: else pmesh->labels = labelNew;
3258: newNext = labelNew;
3259: if (!rank) next = next->next;
3260: }
3261: }
3262: PetscLogEventEnd(DMPLEX_DistributeLabels,dm,0,0,0);
3263: /* Setup hybrid structure */
3264: {
3265: const PetscInt *gpoints;
3266: PetscInt depth, n, d;
3268: for (d = 0; d <= dim; ++d) {pmesh->hybridPointMax[d] = mesh->hybridPointMax[d];}
3269: MPI_Bcast(pmesh->hybridPointMax, dim+1, MPIU_INT, 0, comm);
3270: ISLocalToGlobalMappingGetSize(renumbering, &n);
3271: ISLocalToGlobalMappingGetIndices(renumbering, &gpoints);
3272: DMPlexGetDepth(dm, &depth);
3273: for (d = 0; d <= dim; ++d) {
3274: PetscInt pmax = pmesh->hybridPointMax[d], newmax = 0, pEnd, stratum[2], p;
3276: if (pmax < 0) continue;
3277: DMPlexGetDepthStratum(dm, d > depth ? depth : d, &stratum[0], &stratum[1]);
3278: DMPlexGetDepthStratum(*dmParallel, d, NULL, &pEnd);
3279: MPI_Bcast(stratum, 2, MPIU_INT, 0, comm);
3280: for (p = 0; p < n; ++p) {
3281: const PetscInt point = gpoints[p];
3283: if ((point >= stratum[0]) && (point < stratum[1]) && (point >= pmax)) ++newmax;
3284: }
3285: if (newmax > 0) pmesh->hybridPointMax[d] = pEnd - newmax;
3286: else pmesh->hybridPointMax[d] = -1;
3287: }
3288: ISLocalToGlobalMappingRestoreIndices(renumbering, &gpoints);
3289: }
3290: /* Cleanup Partition */
3291: ISLocalToGlobalMappingDestroy(&renumbering);
3292: PetscSFDestroy(&partSF);
3293: PetscSectionDestroy(&partSection);
3294: ISDestroy(&part);
3295: /* Create point SF for parallel mesh */
3296: PetscLogEventBegin(DMPLEX_DistributeSF,dm,0,0,0);
3297: {
3298: const PetscInt *leaves;
3299: PetscSFNode *remotePoints, *rowners, *lowners;
3300: PetscInt numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3301: PetscInt pStart, pEnd;
3303: DMPlexGetChart(*dmParallel, &pStart, &pEnd);
3304: PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);
3305: PetscMalloc2(numRoots,&rowners,numLeaves,&lowners);
3306: for (p=0; p<numRoots; p++) {
3307: rowners[p].rank = -1;
3308: rowners[p].index = -1;
3309: }
3310: if (origCellPart) {
3311: /* Make sure points in the original partition are not assigned to other procs */
3312: const PetscInt *origPoints;
3314: DMPlexCreatePartitionClosure(dm, origCellPartSection, origCellPart, &origPartSection, &origPart);
3315: ISGetIndices(origPart, &origPoints);
3316: for (p = 0; p < numProcs; ++p) {
3317: PetscInt dof, off, d;
3319: PetscSectionGetDof(origPartSection, p, &dof);
3320: PetscSectionGetOffset(origPartSection, p, &off);
3321: for (d = off; d < off+dof; ++d) {
3322: rowners[origPoints[d]].rank = p;
3323: }
3324: }
3325: ISRestoreIndices(origPart, &origPoints);
3326: ISDestroy(&origPart);
3327: PetscSectionDestroy(&origPartSection);
3328: }
3329: ISDestroy(&origCellPart);
3330: PetscSectionDestroy(&origCellPartSection);
3332: PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);
3333: PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);
3334: for (p = 0; p < numLeaves; ++p) {
3335: if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3336: lowners[p].rank = rank;
3337: lowners[p].index = leaves ? leaves[p] : p;
3338: } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3339: lowners[p].rank = -2;
3340: lowners[p].index = -2;
3341: }
3342: }
3343: for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3344: rowners[p].rank = -3;
3345: rowners[p].index = -3;
3346: }
3347: PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);
3348: PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);
3349: PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);
3350: PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);
3351: for (p = 0; p < numLeaves; ++p) {
3352: if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3353: if (lowners[p].rank != rank) ++numGhostPoints;
3354: }
3355: PetscMalloc1(numGhostPoints, &ghostPoints);
3356: PetscMalloc1(numGhostPoints, &remotePoints);
3357: for (p = 0, gp = 0; p < numLeaves; ++p) {
3358: if (lowners[p].rank != rank) {
3359: ghostPoints[gp] = leaves ? leaves[p] : p;
3360: remotePoints[gp].rank = lowners[p].rank;
3361: remotePoints[gp].index = lowners[p].index;
3362: ++gp;
3363: }
3364: }
3365: PetscFree2(rowners,lowners);
3366: PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);
3367: PetscSFSetFromOptions((*dmParallel)->sf);
3368: }
3369: PetscLogEventEnd(DMPLEX_DistributeSF,dm,0,0,0);
3370: /* Cleanup */
3371: if (sf) {*sf = pointSF;}
3372: else {PetscSFDestroy(&pointSF);}
3373: DMSetFromOptions(*dmParallel);
3374: PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);
3375: return(0);
3376: }
3380: /*@C
3381: DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched.
3383: Input Parameters:
3384: + numCorners - The number of vertices in a cell
3385: - cone - The incoming cone
3387: Output Parameter:
3388: . cone - The inverted cone (in-place)
3390: Level: developer
3392: .seealso: DMPlexGenerate()
3393: @*/
3394: PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[])
3395: {
3396: int tmpc;
3399: if (dim != 3) return(0);
3400: switch (numCorners) {
3401: case 4:
3402: tmpc = cone[0];
3403: cone[0] = cone[1];
3404: cone[1] = tmpc;
3405: break;
3406: case 8:
3407: tmpc = cone[1];
3408: cone[1] = cone[3];
3409: cone[3] = tmpc;
3410: break;
3411: default: break;
3412: }
3413: return(0);
3414: }
3418: /* This is to fix the tetrahedron orientation from TetGen */
3419: PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[])
3420: {
3421: PetscInt bound = numCells*numCorners, coff;
3425: for (coff = 0; coff < bound; coff += numCorners) {
3426: DMPlexInvertCell(dim, numCorners, &cells[coff]);
3427: }
3428: return(0);
3429: }
3431: #if defined(PETSC_HAVE_TRIANGLE)
3432: #include <triangle.h>
3436: PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3437: {
3439: inputCtx->numberofpoints = 0;
3440: inputCtx->numberofpointattributes = 0;
3441: inputCtx->pointlist = NULL;
3442: inputCtx->pointattributelist = NULL;
3443: inputCtx->pointmarkerlist = NULL;
3444: inputCtx->numberofsegments = 0;
3445: inputCtx->segmentlist = NULL;
3446: inputCtx->segmentmarkerlist = NULL;
3447: inputCtx->numberoftriangleattributes = 0;
3448: inputCtx->trianglelist = NULL;
3449: inputCtx->numberofholes = 0;
3450: inputCtx->holelist = NULL;
3451: inputCtx->numberofregions = 0;
3452: inputCtx->regionlist = NULL;
3453: return(0);
3454: }
3458: PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3459: {
3461: outputCtx->numberofpoints = 0;
3462: outputCtx->pointlist = NULL;
3463: outputCtx->pointattributelist = NULL;
3464: outputCtx->pointmarkerlist = NULL;
3465: outputCtx->numberoftriangles = 0;
3466: outputCtx->trianglelist = NULL;
3467: outputCtx->triangleattributelist = NULL;
3468: outputCtx->neighborlist = NULL;
3469: outputCtx->segmentlist = NULL;
3470: outputCtx->segmentmarkerlist = NULL;
3471: outputCtx->numberofedges = 0;
3472: outputCtx->edgelist = NULL;
3473: outputCtx->edgemarkerlist = NULL;
3474: return(0);
3475: }
3479: PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3480: {
3482: free(outputCtx->pointmarkerlist);
3483: free(outputCtx->edgelist);
3484: free(outputCtx->edgemarkerlist);
3485: free(outputCtx->trianglelist);
3486: free(outputCtx->neighborlist);
3487: return(0);
3488: }
3492: PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3493: {
3494: MPI_Comm comm;
3495: PetscInt dim = 2;
3496: const PetscBool createConvexHull = PETSC_FALSE;
3497: const PetscBool constrained = PETSC_FALSE;
3498: struct triangulateio in;
3499: struct triangulateio out;
3500: PetscInt vStart, vEnd, v, eStart, eEnd, e;
3501: PetscMPIInt rank;
3502: PetscErrorCode ierr;
3505: PetscObjectGetComm((PetscObject)boundary,&comm);
3506: MPI_Comm_rank(comm, &rank);
3507: InitInput_Triangle(&in);
3508: InitOutput_Triangle(&out);
3509: DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);
3511: in.numberofpoints = vEnd - vStart;
3512: if (in.numberofpoints > 0) {
3513: PetscSection coordSection;
3514: Vec coordinates;
3515: PetscScalar *array;
3517: PetscMalloc1(in.numberofpoints*dim, &in.pointlist);
3518: PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);
3519: DMGetCoordinatesLocal(boundary, &coordinates);
3520: DMGetCoordinateSection(boundary, &coordSection);
3521: VecGetArray(coordinates, &array);
3522: for (v = vStart; v < vEnd; ++v) {
3523: const PetscInt idx = v - vStart;
3524: PetscInt off, d;
3526: PetscSectionGetOffset(coordSection, v, &off);
3527: for (d = 0; d < dim; ++d) {
3528: in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3529: }
3530: DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);
3531: }
3532: VecRestoreArray(coordinates, &array);
3533: }
3534: DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);
3535: in.numberofsegments = eEnd - eStart;
3536: if (in.numberofsegments > 0) {
3537: PetscMalloc1(in.numberofsegments*2, &in.segmentlist);
3538: PetscMalloc1(in.numberofsegments, &in.segmentmarkerlist);
3539: for (e = eStart; e < eEnd; ++e) {
3540: const PetscInt idx = e - eStart;
3541: const PetscInt *cone;
3543: DMPlexGetCone(boundary, e, &cone);
3545: in.segmentlist[idx*2+0] = cone[0] - vStart;
3546: in.segmentlist[idx*2+1] = cone[1] - vStart;
3548: DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);
3549: }
3550: }
3551: #if 0 /* Do not currently support holes */
3552: PetscReal *holeCoords;
3553: PetscInt h, d;
3555: DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);
3556: if (in.numberofholes > 0) {
3557: PetscMalloc1(in.numberofholes*dim, &in.holelist);
3558: for (h = 0; h < in.numberofholes; ++h) {
3559: for (d = 0; d < dim; ++d) {
3560: in.holelist[h*dim+d] = holeCoords[h*dim+d];
3561: }
3562: }
3563: }
3564: #endif
3565: if (!rank) {
3566: char args[32];
3568: /* Take away 'Q' for verbose output */
3569: PetscStrcpy(args, "pqezQ");
3570: if (createConvexHull) {
3571: PetscStrcat(args, "c");
3572: }
3573: if (constrained) {
3574: PetscStrcpy(args, "zepDQ");
3575: }
3576: triangulate(args, &in, &out, NULL);
3577: }
3578: PetscFree(in.pointlist);
3579: PetscFree(in.pointmarkerlist);
3580: PetscFree(in.segmentlist);
3581: PetscFree(in.segmentmarkerlist);
3582: PetscFree(in.holelist);
3584: {
3585: const PetscInt numCorners = 3;
3586: const PetscInt numCells = out.numberoftriangles;
3587: const PetscInt numVertices = out.numberofpoints;
3588: const int *cells = out.trianglelist;
3589: const double *meshCoords = out.pointlist;
3591: DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);
3592: /* Set labels */
3593: for (v = 0; v < numVertices; ++v) {
3594: if (out.pointmarkerlist[v]) {
3595: DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);
3596: }
3597: }
3598: if (interpolate) {
3599: for (e = 0; e < out.numberofedges; e++) {
3600: if (out.edgemarkerlist[e]) {
3601: const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3602: const PetscInt *edges;
3603: PetscInt numEdges;
3605: DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);
3606: if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3607: DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);
3608: DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);
3609: }
3610: }
3611: }
3612: DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
3613: }
3614: #if 0 /* Do not currently support holes */
3615: DMPlexCopyHoles(*dm, boundary);
3616: #endif
3617: FiniOutput_Triangle(&out);
3618: return(0);
3619: }
3623: PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3624: {
3625: MPI_Comm comm;
3626: PetscInt dim = 2;
3627: struct triangulateio in;
3628: struct triangulateio out;
3629: PetscInt vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3630: PetscMPIInt rank;
3631: PetscErrorCode ierr;
3634: PetscObjectGetComm((PetscObject)dm,&comm);
3635: MPI_Comm_rank(comm, &rank);
3636: InitInput_Triangle(&in);
3637: InitOutput_Triangle(&out);
3638: DMPlexGetDepth(dm, &depth);
3639: MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);
3640: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
3642: in.numberofpoints = vEnd - vStart;
3643: if (in.numberofpoints > 0) {
3644: PetscSection coordSection;
3645: Vec coordinates;
3646: PetscScalar *array;
3648: PetscMalloc1(in.numberofpoints*dim, &in.pointlist);
3649: PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);
3650: DMGetCoordinatesLocal(dm, &coordinates);
3651: DMGetCoordinateSection(dm, &coordSection);
3652: VecGetArray(coordinates, &array);
3653: for (v = vStart; v < vEnd; ++v) {
3654: const PetscInt idx = v - vStart;
3655: PetscInt off, d;
3657: PetscSectionGetOffset(coordSection, v, &off);
3658: for (d = 0; d < dim; ++d) {
3659: in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3660: }
3661: DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);
3662: }
3663: VecRestoreArray(coordinates, &array);
3664: }
3665: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
3667: in.numberofcorners = 3;
3668: in.numberoftriangles = cEnd - cStart;
3670: in.trianglearealist = (double*) maxVolumes;
3671: if (in.numberoftriangles > 0) {
3672: PetscMalloc1(in.numberoftriangles*in.numberofcorners, &in.trianglelist);
3673: for (c = cStart; c < cEnd; ++c) {
3674: const PetscInt idx = c - cStart;
3675: PetscInt *closure = NULL;
3676: PetscInt closureSize;
3678: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3679: if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3680: for (v = 0; v < 3; ++v) {
3681: in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3682: }
3683: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3684: }
3685: }
3686: /* TODO: Segment markers are missing on input */
3687: #if 0 /* Do not currently support holes */
3688: PetscReal *holeCoords;
3689: PetscInt h, d;
3691: DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);
3692: if (in.numberofholes > 0) {
3693: PetscMalloc1(in.numberofholes*dim, &in.holelist);
3694: for (h = 0; h < in.numberofholes; ++h) {
3695: for (d = 0; d < dim; ++d) {
3696: in.holelist[h*dim+d] = holeCoords[h*dim+d];
3697: }
3698: }
3699: }
3700: #endif
3701: if (!rank) {
3702: char args[32];
3704: /* Take away 'Q' for verbose output */
3705: PetscStrcpy(args, "pqezQra");
3706: triangulate(args, &in, &out, NULL);
3707: }
3708: PetscFree(in.pointlist);
3709: PetscFree(in.pointmarkerlist);
3710: PetscFree(in.segmentlist);
3711: PetscFree(in.segmentmarkerlist);
3712: PetscFree(in.trianglelist);
3714: {
3715: const PetscInt numCorners = 3;
3716: const PetscInt numCells = out.numberoftriangles;
3717: const PetscInt numVertices = out.numberofpoints;
3718: const int *cells = out.trianglelist;
3719: const double *meshCoords = out.pointlist;
3720: PetscBool interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3722: DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);
3723: /* Set labels */
3724: for (v = 0; v < numVertices; ++v) {
3725: if (out.pointmarkerlist[v]) {
3726: DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);
3727: }
3728: }
3729: if (interpolate) {
3730: PetscInt e;
3732: for (e = 0; e < out.numberofedges; e++) {
3733: if (out.edgemarkerlist[e]) {
3734: const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3735: const PetscInt *edges;
3736: PetscInt numEdges;
3738: DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3739: if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3740: DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);
3741: DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3742: }
3743: }
3744: }
3745: DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);
3746: }
3747: #if 0 /* Do not currently support holes */
3748: DMPlexCopyHoles(*dm, boundary);
3749: #endif
3750: FiniOutput_Triangle(&out);
3751: return(0);
3752: }
3753: #endif
3755: #if defined(PETSC_HAVE_TETGEN)
3756: #include <tetgen.h>
3759: PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3760: {
3761: MPI_Comm comm;
3762: const PetscInt dim = 3;
3763: ::tetgenio in;
3764: ::tetgenio out;
3765: PetscInt vStart, vEnd, v, fStart, fEnd, f;
3766: PetscMPIInt rank;
3770: PetscObjectGetComm((PetscObject)boundary,&comm);
3771: MPI_Comm_rank(comm, &rank);
3772: DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);
3773: in.numberofpoints = vEnd - vStart;
3774: if (in.numberofpoints > 0) {
3775: PetscSection coordSection;
3776: Vec coordinates;
3777: PetscScalar *array;
3779: in.pointlist = new double[in.numberofpoints*dim];
3780: in.pointmarkerlist = new int[in.numberofpoints];
3782: DMGetCoordinatesLocal(boundary, &coordinates);
3783: DMGetCoordinateSection(boundary, &coordSection);
3784: VecGetArray(coordinates, &array);
3785: for (v = vStart; v < vEnd; ++v) {
3786: const PetscInt idx = v - vStart;
3787: PetscInt off, d;
3789: PetscSectionGetOffset(coordSection, v, &off);
3790: for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3791: DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);
3792: }
3793: VecRestoreArray(coordinates, &array);
3794: }
3795: DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);
3797: in.numberoffacets = fEnd - fStart;
3798: if (in.numberoffacets > 0) {
3799: in.facetlist = new tetgenio::facet[in.numberoffacets];
3800: in.facetmarkerlist = new int[in.numberoffacets];
3801: for (f = fStart; f < fEnd; ++f) {
3802: const PetscInt idx = f - fStart;
3803: PetscInt *points = NULL, numPoints, p, numVertices = 0, v;
3805: in.facetlist[idx].numberofpolygons = 1;
3806: in.facetlist[idx].polygonlist = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3807: in.facetlist[idx].numberofholes = 0;
3808: in.facetlist[idx].holelist = NULL;
3810: DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
3811: for (p = 0; p < numPoints*2; p += 2) {
3812: const PetscInt point = points[p];
3813: if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3814: }
3816: tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3817: poly->numberofvertices = numVertices;
3818: poly->vertexlist = new int[poly->numberofvertices];
3819: for (v = 0; v < numVertices; ++v) {
3820: const PetscInt vIdx = points[v] - vStart;
3821: poly->vertexlist[v] = vIdx;
3822: }
3823: DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);
3824: DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
3825: }
3826: }
3827: if (!rank) {
3828: char args[32];
3830: /* Take away 'Q' for verbose output */
3831: PetscStrcpy(args, "pqezQ");
3832: ::tetrahedralize(args, &in, &out);
3833: }
3834: {
3835: const PetscInt numCorners = 4;
3836: const PetscInt numCells = out.numberoftetrahedra;
3837: const PetscInt numVertices = out.numberofpoints;
3838: const double *meshCoords = out.pointlist;
3839: int *cells = out.tetrahedronlist;
3841: DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);
3842: DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);
3843: /* Set labels */
3844: for (v = 0; v < numVertices; ++v) {
3845: if (out.pointmarkerlist[v]) {
3846: DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);
3847: }
3848: }
3849: if (interpolate) {
3850: PetscInt e;
3852: for (e = 0; e < out.numberofedges; e++) {
3853: if (out.edgemarkerlist[e]) {
3854: const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3855: const PetscInt *edges;
3856: PetscInt numEdges;
3858: DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);
3859: if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3860: DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);
3861: DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);
3862: }
3863: }
3864: for (f = 0; f < out.numberoftrifaces; f++) {
3865: if (out.trifacemarkerlist[f]) {
3866: const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3867: const PetscInt *faces;
3868: PetscInt numFaces;
3870: DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);
3871: if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3872: DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);
3873: DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);
3874: }
3875: }
3876: }
3877: DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
3878: }
3879: return(0);
3880: }
3884: PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3885: {
3886: MPI_Comm comm;
3887: const PetscInt dim = 3;
3888: ::tetgenio in;
3889: ::tetgenio out;
3890: PetscInt vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3891: PetscMPIInt rank;
3895: PetscObjectGetComm((PetscObject)dm,&comm);
3896: MPI_Comm_rank(comm, &rank);
3897: DMPlexGetDepth(dm, &depth);
3898: MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);
3899: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
3901: in.numberofpoints = vEnd - vStart;
3902: if (in.numberofpoints > 0) {
3903: PetscSection coordSection;
3904: Vec coordinates;
3905: PetscScalar *array;
3907: in.pointlist = new double[in.numberofpoints*dim];
3908: in.pointmarkerlist = new int[in.numberofpoints];
3910: DMGetCoordinatesLocal(dm, &coordinates);
3911: DMGetCoordinateSection(dm, &coordSection);
3912: VecGetArray(coordinates, &array);
3913: for (v = vStart; v < vEnd; ++v) {
3914: const PetscInt idx = v - vStart;
3915: PetscInt off, d;
3917: PetscSectionGetOffset(coordSection, v, &off);
3918: for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3919: DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);
3920: }
3921: VecRestoreArray(coordinates, &array);
3922: }
3923: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
3925: in.numberofcorners = 4;
3926: in.numberoftetrahedra = cEnd - cStart;
3927: in.tetrahedronvolumelist = (double*) maxVolumes;
3928: if (in.numberoftetrahedra > 0) {
3929: in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3930: for (c = cStart; c < cEnd; ++c) {
3931: const PetscInt idx = c - cStart;
3932: PetscInt *closure = NULL;
3933: PetscInt closureSize;
3935: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3936: if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3937: for (v = 0; v < 4; ++v) {
3938: in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3939: }
3940: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3941: }
3942: }
3943: /* TODO: Put in boundary faces with markers */
3944: if (!rank) {
3945: char args[32];
3947: /* Take away 'Q' for verbose output */
3948: /*PetscStrcpy(args, "qezQra"); */
3949: PetscStrcpy(args, "qezraVVVV");
3950: ::tetrahedralize(args, &in, &out);
3951: }
3952: in.tetrahedronvolumelist = NULL;
3954: {
3955: const PetscInt numCorners = 4;
3956: const PetscInt numCells = out.numberoftetrahedra;
3957: const PetscInt numVertices = out.numberofpoints;
3958: const double *meshCoords = out.pointlist;
3959: int *cells = out.tetrahedronlist;
3961: PetscBool interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3963: DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);
3964: DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);
3965: /* Set labels */
3966: for (v = 0; v < numVertices; ++v) {
3967: if (out.pointmarkerlist[v]) {
3968: DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);
3969: }
3970: }
3971: if (interpolate) {
3972: PetscInt e, f;
3974: for (e = 0; e < out.numberofedges; e++) {
3975: if (out.edgemarkerlist[e]) {
3976: const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3977: const PetscInt *edges;
3978: PetscInt numEdges;
3980: DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3981: if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3982: DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);
3983: DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3984: }
3985: }
3986: for (f = 0; f < out.numberoftrifaces; f++) {
3987: if (out.trifacemarkerlist[f]) {
3988: const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3989: const PetscInt *faces;
3990: PetscInt numFaces;
3992: DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);
3993: if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3994: DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);
3995: DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);
3996: }
3997: }
3998: }
3999: DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);
4000: }
4001: return(0);
4002: }
4003: #endif
4005: #if defined(PETSC_HAVE_CTETGEN)
4006: #include <ctetgen.h>
4010: PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4011: {
4012: MPI_Comm comm;
4013: const PetscInt dim = 3;
4014: PLC *in, *out;
4015: PetscInt verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4016: PetscMPIInt rank;
4020: PetscObjectGetComm((PetscObject)boundary,&comm);
4021: PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);
4022: MPI_Comm_rank(comm, &rank);
4023: DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);
4024: PLCCreate(&in);
4025: PLCCreate(&out);
4027: in->numberofpoints = vEnd - vStart;
4028: if (in->numberofpoints > 0) {
4029: PetscSection coordSection;
4030: Vec coordinates;
4031: PetscScalar *array;
4033: PetscMalloc1(in->numberofpoints*dim, &in->pointlist);
4034: PetscMalloc1(in->numberofpoints, &in->pointmarkerlist);
4035: DMGetCoordinatesLocal(boundary, &coordinates);
4036: DMGetCoordinateSection(boundary, &coordSection);
4037: VecGetArray(coordinates, &array);
4038: for (v = vStart; v < vEnd; ++v) {
4039: const PetscInt idx = v - vStart;
4040: PetscInt off, d, m;
4042: PetscSectionGetOffset(coordSection, v, &off);
4043: for (d = 0; d < dim; ++d) {
4044: in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4045: }
4046: DMPlexGetLabelValue(boundary, "marker", v, &m);
4048: in->pointmarkerlist[idx] = (int) m;
4049: }
4050: VecRestoreArray(coordinates, &array);
4051: }
4052: DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);
4054: in->numberoffacets = fEnd - fStart;
4055: if (in->numberoffacets > 0) {
4056: PetscMalloc1(in->numberoffacets, &in->facetlist);
4057: PetscMalloc1(in->numberoffacets, &in->facetmarkerlist);
4058: for (f = fStart; f < fEnd; ++f) {
4059: const PetscInt idx = f - fStart;
4060: PetscInt *points = NULL, numPoints, p, numVertices = 0, v, m;
4061: polygon *poly;
4063: in->facetlist[idx].numberofpolygons = 1;
4065: PetscMalloc1(in->facetlist[idx].numberofpolygons, &in->facetlist[idx].polygonlist);
4067: in->facetlist[idx].numberofholes = 0;
4068: in->facetlist[idx].holelist = NULL;
4070: DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
4071: for (p = 0; p < numPoints*2; p += 2) {
4072: const PetscInt point = points[p];
4073: if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4074: }
4076: poly = in->facetlist[idx].polygonlist;
4077: poly->numberofvertices = numVertices;
4078: PetscMalloc1(poly->numberofvertices, &poly->vertexlist);
4079: for (v = 0; v < numVertices; ++v) {
4080: const PetscInt vIdx = points[v] - vStart;
4081: poly->vertexlist[v] = vIdx;
4082: }
4083: DMPlexGetLabelValue(boundary, "marker", f, &m);
4084: in->facetmarkerlist[idx] = (int) m;
4085: DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
4086: }
4087: }
4088: if (!rank) {
4089: TetGenOpts t;
4091: TetGenOptsInitialize(&t);
4092: t.in = boundary; /* Should go away */
4093: t.plc = 1;
4094: t.quality = 1;
4095: t.edgesout = 1;
4096: t.zeroindex = 1;
4097: t.quiet = 1;
4098: t.verbose = verbose;
4099: TetGenCheckOpts(&t);
4100: TetGenTetrahedralize(&t, in, out);
4101: }
4102: {
4103: const PetscInt numCorners = 4;
4104: const PetscInt numCells = out->numberoftetrahedra;
4105: const PetscInt numVertices = out->numberofpoints;
4106: const double *meshCoords = out->pointlist;
4107: int *cells = out->tetrahedronlist;
4109: DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);
4110: DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);
4111: /* Set labels */
4112: for (v = 0; v < numVertices; ++v) {
4113: if (out->pointmarkerlist[v]) {
4114: DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);
4115: }
4116: }
4117: if (interpolate) {
4118: PetscInt e;
4120: for (e = 0; e < out->numberofedges; e++) {
4121: if (out->edgemarkerlist[e]) {
4122: const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4123: const PetscInt *edges;
4124: PetscInt numEdges;
4126: DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);
4127: if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4128: DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);
4129: DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);
4130: }
4131: }
4132: for (f = 0; f < out->numberoftrifaces; f++) {
4133: if (out->trifacemarkerlist[f]) {
4134: const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4135: const PetscInt *faces;
4136: PetscInt numFaces;
4138: DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);
4139: if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4140: DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);
4141: DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);
4142: }
4143: }
4144: }
4145: DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
4146: }
4148: PLCDestroy(&in);
4149: PLCDestroy(&out);
4150: return(0);
4151: }
4155: PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
4156: {
4157: MPI_Comm comm;
4158: const PetscInt dim = 3;
4159: PLC *in, *out;
4160: PetscInt verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4161: PetscMPIInt rank;
4165: PetscObjectGetComm((PetscObject)dm,&comm);
4166: PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);
4167: MPI_Comm_rank(comm, &rank);
4168: DMPlexGetDepth(dm, &depth);
4169: MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);
4170: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
4171: PLCCreate(&in);
4172: PLCCreate(&out);
4174: in->numberofpoints = vEnd - vStart;
4175: if (in->numberofpoints > 0) {
4176: PetscSection coordSection;
4177: Vec coordinates;
4178: PetscScalar *array;
4180: PetscMalloc1(in->numberofpoints*dim, &in->pointlist);
4181: PetscMalloc1(in->numberofpoints, &in->pointmarkerlist);
4182: DMGetCoordinatesLocal(dm, &coordinates);
4183: DMGetCoordinateSection(dm, &coordSection);
4184: VecGetArray(coordinates, &array);
4185: for (v = vStart; v < vEnd; ++v) {
4186: const PetscInt idx = v - vStart;
4187: PetscInt off, d, m;
4189: PetscSectionGetOffset(coordSection, v, &off);
4190: for (d = 0; d < dim; ++d) {
4191: in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4192: }
4193: DMPlexGetLabelValue(dm, "marker", v, &m);
4195: in->pointmarkerlist[idx] = (int) m;
4196: }
4197: VecRestoreArray(coordinates, &array);
4198: }
4199: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
4201: in->numberofcorners = 4;
4202: in->numberoftetrahedra = cEnd - cStart;
4203: in->tetrahedronvolumelist = maxVolumes;
4204: if (in->numberoftetrahedra > 0) {
4205: PetscMalloc1(in->numberoftetrahedra*in->numberofcorners, &in->tetrahedronlist);
4206: for (c = cStart; c < cEnd; ++c) {
4207: const PetscInt idx = c - cStart;
4208: PetscInt *closure = NULL;
4209: PetscInt closureSize;
4211: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
4212: if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4213: for (v = 0; v < 4; ++v) {
4214: in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4215: }
4216: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
4217: }
4218: }
4219: if (!rank) {
4220: TetGenOpts t;
4222: TetGenOptsInitialize(&t);
4224: t.in = dm; /* Should go away */
4225: t.refine = 1;
4226: t.varvolume = 1;
4227: t.quality = 1;
4228: t.edgesout = 1;
4229: t.zeroindex = 1;
4230: t.quiet = 1;
4231: t.verbose = verbose; /* Change this */
4233: TetGenCheckOpts(&t);
4234: TetGenTetrahedralize(&t, in, out);
4235: }
4236: {
4237: const PetscInt numCorners = 4;
4238: const PetscInt numCells = out->numberoftetrahedra;
4239: const PetscInt numVertices = out->numberofpoints;
4240: const double *meshCoords = out->pointlist;
4241: int *cells = out->tetrahedronlist;
4242: PetscBool interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4244: DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);
4245: DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);
4246: /* Set labels */
4247: for (v = 0; v < numVertices; ++v) {
4248: if (out->pointmarkerlist[v]) {
4249: DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);
4250: }
4251: }
4252: if (interpolate) {
4253: PetscInt e, f;
4255: for (e = 0; e < out->numberofedges; e++) {
4256: if (out->edgemarkerlist[e]) {
4257: const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4258: const PetscInt *edges;
4259: PetscInt numEdges;
4261: DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);
4262: if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4263: DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);
4264: DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);
4265: }
4266: }
4267: for (f = 0; f < out->numberoftrifaces; f++) {
4268: if (out->trifacemarkerlist[f]) {
4269: const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4270: const PetscInt *faces;
4271: PetscInt numFaces;
4273: DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);
4274: if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4275: DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);
4276: DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);
4277: }
4278: }
4279: }
4280: DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);
4281: }
4282: PLCDestroy(&in);
4283: PLCDestroy(&out);
4284: return(0);
4285: }
4286: #endif
4290: /*@C
4291: DMPlexGenerate - Generates a mesh.
4293: Not Collective
4295: Input Parameters:
4296: + boundary - The DMPlex boundary object
4297: . name - The mesh generation package name
4298: - interpolate - Flag to create intermediate mesh elements
4300: Output Parameter:
4301: . mesh - The DMPlex object
4303: Level: intermediate
4305: .keywords: mesh, elements
4306: .seealso: DMPlexCreate(), DMRefine()
4307: @*/
4308: PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
4309: {
4310: PetscInt dim;
4311: char genname[1024];
4312: PetscBool isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4318: DMPlexGetDimension(boundary, &dim);
4319: PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);
4320: if (flg) name = genname;
4321: if (name) {
4322: PetscStrcmp(name, "triangle", &isTriangle);
4323: PetscStrcmp(name, "tetgen", &isTetgen);
4324: PetscStrcmp(name, "ctetgen", &isCTetgen);
4325: }
4326: switch (dim) {
4327: case 1:
4328: if (!name || isTriangle) {
4329: #if defined(PETSC_HAVE_TRIANGLE)
4330: DMPlexGenerate_Triangle(boundary, interpolate, mesh);
4331: #else
4332: SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4333: #endif
4334: } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4335: break;
4336: case 2:
4337: if (!name || isCTetgen) {
4338: #if defined(PETSC_HAVE_CTETGEN)
4339: DMPlexGenerate_CTetgen(boundary, interpolate, mesh);
4340: #else
4341: SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4342: #endif
4343: } else if (isTetgen) {
4344: #if defined(PETSC_HAVE_TETGEN)
4345: DMPlexGenerate_Tetgen(boundary, interpolate, mesh);
4346: #else
4347: SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4348: #endif
4349: } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4350: break;
4351: default:
4352: SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4353: }
4354: return(0);
4355: }
4359: PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
4360: {
4361: PetscReal refinementLimit;
4362: PetscInt dim, cStart, cEnd;
4363: char genname[1024], *name = NULL;
4364: PetscBool isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4368: DMPlexGetRefinementUniform(dm, &isUniform);
4369: if (isUniform) {
4370: CellRefiner cellRefiner;
4372: DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
4373: DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
4374: return(0);
4375: }
4376: DMPlexGetRefinementLimit(dm, &refinementLimit);
4377: if (refinementLimit == 0.0) return(0);
4378: DMPlexGetDimension(dm, &dim);
4379: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
4380: PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);
4381: if (flg) name = genname;
4382: if (name) {
4383: PetscStrcmp(name, "triangle", &isTriangle);
4384: PetscStrcmp(name, "tetgen", &isTetgen);
4385: PetscStrcmp(name, "ctetgen", &isCTetgen);
4386: }
4387: switch (dim) {
4388: case 2:
4389: if (!name || isTriangle) {
4390: #if defined(PETSC_HAVE_TRIANGLE)
4391: double *maxVolumes;
4392: PetscInt c;
4394: PetscMalloc1((cEnd - cStart), &maxVolumes);
4395: for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4396: DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);
4397: PetscFree(maxVolumes);
4398: #else
4399: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
4400: #endif
4401: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4402: break;
4403: case 3:
4404: if (!name || isCTetgen) {
4405: #if defined(PETSC_HAVE_CTETGEN)
4406: PetscReal *maxVolumes;
4407: PetscInt c;
4409: PetscMalloc1((cEnd - cStart), &maxVolumes);
4410: for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4411: DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);
4412: #else
4413: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4414: #endif
4415: } else if (isTetgen) {
4416: #if defined(PETSC_HAVE_TETGEN)
4417: double *maxVolumes;
4418: PetscInt c;
4420: PetscMalloc1((cEnd - cStart), &maxVolumes);
4421: for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4422: DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);
4423: #else
4424: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4425: #endif
4426: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4427: break;
4428: default:
4429: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
4430: }
4431: return(0);
4432: }
4436: /*@
4437: DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4439: Not Collective
4441: Input Parameter:
4442: . dm - The DMPlex object
4444: Output Parameter:
4445: . depthLabel - The DMLabel recording point depth
4447: Level: developer
4449: .keywords: mesh, points
4450: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
4451: @*/
4452: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4453: {
4454: DM_Plex *mesh = (DM_Plex*) dm->data;
4460: if (!mesh->depthLabel) {DMPlexGetLabel(dm, "depth", &mesh->depthLabel);}
4461: *depthLabel = mesh->depthLabel;
4462: return(0);
4463: }
4467: /*@
4468: DMPlexGetDepth - Get the depth of the DAG representing this mesh
4470: Not Collective
4472: Input Parameter:
4473: . dm - The DMPlex object
4475: Output Parameter:
4476: . depth - The number of strata (breadth first levels) in the DAG
4478: Level: developer
4480: .keywords: mesh, points
4481: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
4482: @*/
4483: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4484: {
4485: DMLabel label;
4486: PetscInt d = 0;
4492: DMPlexGetDepthLabel(dm, &label);
4493: if (label) {DMLabelGetNumValues(label, &d);}
4494: *depth = d-1;
4495: return(0);
4496: }
4500: /*@
4501: DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4503: Not Collective
4505: Input Parameters:
4506: + dm - The DMPlex object
4507: - stratumValue - The requested depth
4509: Output Parameters:
4510: + start - The first point at this depth
4511: - end - One beyond the last point at this depth
4513: Level: developer
4515: .keywords: mesh, points
4516: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
4517: @*/
4518: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4519: {
4520: DMLabel label;
4521: PetscInt pStart, pEnd;
4528: DMPlexGetChart(dm, &pStart, &pEnd);
4529: if (pStart == pEnd) return(0);
4530: if (stratumValue < 0) {
4531: if (start) *start = pStart;
4532: if (end) *end = pEnd;
4533: return(0);
4534: }
4535: DMPlexGetDepthLabel(dm, &label);
4536: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4537: DMLabelGetStratumBounds(label, stratumValue, start, end);
4538: return(0);
4539: }
4543: /*@
4544: DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4546: Not Collective
4548: Input Parameters:
4549: + dm - The DMPlex object
4550: - stratumValue - The requested height
4552: Output Parameters:
4553: + start - The first point at this height
4554: - end - One beyond the last point at this height
4556: Level: developer
4558: .keywords: mesh, points
4559: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
4560: @*/
4561: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4562: {
4563: DMLabel label;
4564: PetscInt depth, pStart, pEnd;
4571: DMPlexGetChart(dm, &pStart, &pEnd);
4572: if (pStart == pEnd) return(0);
4573: if (stratumValue < 0) {
4574: if (start) *start = pStart;
4575: if (end) *end = pEnd;
4576: return(0);
4577: }
4578: DMPlexGetDepthLabel(dm, &label);
4579: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4580: DMLabelGetNumValues(label, &depth);
4581: DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
4582: return(0);
4583: }
4587: /* Set the number of dof on each point and separate by fields */
4588: PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
4589: {
4590: PetscInt *numDofTot;
4591: PetscInt depth, pStart = 0, pEnd = 0;
4592: PetscInt p, d, dep, f;
4596: PetscMalloc1((dim+1), &numDofTot);
4597: for (d = 0; d <= dim; ++d) {
4598: numDofTot[d] = 0;
4599: for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
4600: }
4601: PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
4602: if (numFields > 0) {
4603: PetscSectionSetNumFields(*section, numFields);
4604: if (numComp) {
4605: for (f = 0; f < numFields; ++f) {
4606: PetscSectionSetFieldComponents(*section, f, numComp[f]);
4607: }
4608: }
4609: }
4610: DMPlexGetChart(dm, &pStart, &pEnd);
4611: PetscSectionSetChart(*section, pStart, pEnd);
4612: DMPlexGetDepth(dm, &depth);
4613: for (dep = 0; dep <= depth; ++dep) {
4614: d = dim == depth ? dep : (!dep ? 0 : dim);
4615: DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
4616: for (p = pStart; p < pEnd; ++p) {
4617: for (f = 0; f < numFields; ++f) {
4618: PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
4619: }
4620: PetscSectionSetDof(*section, p, numDofTot[d]);
4621: }
4622: }
4623: PetscFree(numDofTot);
4624: return(0);
4625: }
4629: /* Set the number of dof on each point and separate by fields
4630: If constDof is PETSC_DETERMINE, constrain every dof on the point
4631: */
4632: PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
4633: {
4634: PetscInt numFields;
4635: PetscInt bc;
4639: PetscSectionGetNumFields(section, &numFields);
4640: for (bc = 0; bc < numBC; ++bc) {
4641: PetscInt field = 0;
4642: const PetscInt *idx;
4643: PetscInt n, i;
4645: if (numFields) field = bcField[bc];
4646: ISGetLocalSize(bcPoints[bc], &n);
4647: ISGetIndices(bcPoints[bc], &idx);
4648: for (i = 0; i < n; ++i) {
4649: const PetscInt p = idx[i];
4650: PetscInt numConst = constDof;
4652: /* Constrain every dof on the point */
4653: if (numConst < 0) {
4654: if (numFields) {
4655: PetscSectionGetFieldDof(section, p, field, &numConst);
4656: } else {
4657: PetscSectionGetDof(section, p, &numConst);
4658: }
4659: }
4660: if (numFields) {
4661: PetscSectionAddFieldConstraintDof(section, p, field, numConst);
4662: }
4663: PetscSectionAddConstraintDof(section, p, numConst);
4664: }
4665: ISRestoreIndices(bcPoints[bc], &idx);
4666: }
4667: return(0);
4668: }
4672: /* Set the constrained indices on each point and separate by fields */
4673: PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
4674: {
4675: PetscInt *maxConstraints;
4676: PetscInt numFields, f, pStart = 0, pEnd = 0, p;
4680: PetscSectionGetNumFields(section, &numFields);
4681: PetscSectionGetChart(section, &pStart, &pEnd);
4682: PetscMalloc1((numFields+1), &maxConstraints);
4683: for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
4684: for (p = pStart; p < pEnd; ++p) {
4685: PetscInt cdof;
4687: if (numFields) {
4688: for (f = 0; f < numFields; ++f) {
4689: PetscSectionGetFieldConstraintDof(section, p, f, &cdof);
4690: maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
4691: }
4692: } else {
4693: PetscSectionGetConstraintDof(section, p, &cdof);
4694: maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
4695: }
4696: }
4697: for (f = 0; f < numFields; ++f) {
4698: maxConstraints[numFields] += maxConstraints[f];
4699: }
4700: if (maxConstraints[numFields]) {
4701: PetscInt *indices;
4703: PetscMalloc1(maxConstraints[numFields], &indices);
4704: for (p = pStart; p < pEnd; ++p) {
4705: PetscInt cdof, d;
4707: PetscSectionGetConstraintDof(section, p, &cdof);
4708: if (cdof) {
4709: if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
4710: if (numFields) {
4711: PetscInt numConst = 0, foff = 0;
4713: for (f = 0; f < numFields; ++f) {
4714: PetscInt cfdof, fdof;
4716: PetscSectionGetFieldDof(section, p, f, &fdof);
4717: PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);
4718: /* Change constraint numbering from absolute local dof number to field relative local dof number */
4719: for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
4720: PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);
4721: for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
4722: numConst += cfdof;
4723: foff += fdof;
4724: }
4725: if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4726: } else {
4727: for (d = 0; d < cdof; ++d) indices[d] = d;
4728: }
4729: PetscSectionSetConstraintIndices(section, p, indices);
4730: }
4731: }
4732: PetscFree(indices);
4733: }
4734: PetscFree(maxConstraints);
4735: return(0);
4736: }
4740: /* Set the constrained field indices on each point */
4741: PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
4742: {
4743: const PetscInt *points, *indices;
4744: PetscInt numFields, maxDof, numPoints, p, numConstraints;
4745: PetscErrorCode ierr;
4748: PetscSectionGetNumFields(section, &numFields);
4749: if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
4751: ISGetLocalSize(bcPoints, &numPoints);
4752: ISGetIndices(bcPoints, &points);
4753: if (!constraintIndices) {
4754: PetscInt *idx, i;
4756: PetscSectionGetMaxDof(section, &maxDof);
4757: PetscMalloc1(maxDof, &idx);
4758: for (i = 0; i < maxDof; ++i) idx[i] = i;
4759: for (p = 0; p < numPoints; ++p) {
4760: PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);
4761: }
4762: PetscFree(idx);
4763: } else {
4764: ISGetLocalSize(constraintIndices, &numConstraints);
4765: ISGetIndices(constraintIndices, &indices);
4766: for (p = 0; p < numPoints; ++p) {
4767: PetscInt fcdof;
4769: PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);
4770: if (fcdof != numConstraints) SETERRQ4(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
4771: PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);
4772: }
4773: ISRestoreIndices(constraintIndices, &indices);
4774: }
4775: ISRestoreIndices(bcPoints, &points);
4776: return(0);
4777: }
4781: /* Set the constrained indices on each point and separate by fields */
4782: PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
4783: {
4784: PetscInt *indices;
4785: PetscInt numFields, maxDof, f, pStart = 0, pEnd = 0, p;
4789: PetscSectionGetMaxDof(section, &maxDof);
4790: PetscMalloc1(maxDof, &indices);
4791: PetscSectionGetNumFields(section, &numFields);
4792: if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
4793: PetscSectionGetChart(section, &pStart, &pEnd);
4794: for (p = pStart; p < pEnd; ++p) {
4795: PetscInt cdof, d;
4797: PetscSectionGetConstraintDof(section, p, &cdof);
4798: if (cdof) {
4799: PetscInt numConst = 0, foff = 0;
4801: for (f = 0; f < numFields; ++f) {
4802: const PetscInt *fcind;
4803: PetscInt fdof, fcdof;
4805: PetscSectionGetFieldDof(section, p, f, &fdof);
4806: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
4807: if (fcdof) {PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);}
4808: /* Change constraint numbering from field relative local dof number to absolute local dof number */
4809: for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
4810: foff += fdof;
4811: numConst += fcdof;
4812: }
4813: if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4814: PetscSectionSetConstraintIndices(section, p, indices);
4815: }
4816: }
4817: PetscFree(indices);
4818: return(0);
4819: }
4823: /*@C
4824: DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
4826: Not Collective
4828: Input Parameters:
4829: + dm - The DMPlex object
4830: . dim - The spatial dimension of the problem
4831: . numFields - The number of fields in the problem
4832: . numComp - An array of size numFields that holds the number of components for each field
4833: . numDof - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
4834: . numBC - The number of boundary conditions
4835: . bcField - An array of size numBC giving the field number for each boundry condition
4836: - bcPoints - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
4838: Output Parameter:
4839: . section - The PetscSection object
4841: Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the
4842: nubmer of dof for field 0 on each edge.
4844: Level: developer
4846: Fortran Notes:
4847: A Fortran 90 version is available as DMPlexCreateSectionF90()
4849: .keywords: mesh, elements
4850: .seealso: DMPlexCreate(), PetscSectionCreate()
4851: @*/
4852: PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
4853: {
4857: DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
4858: DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);
4859: PetscSectionSetUp(*section);
4860: if (numBC) {DMPlexCreateSectionBCIndicesAll(dm, *section);}
4861: PetscSectionViewFromOptions(*section,NULL,"-section_view");
4862: return(0);
4863: }
4867: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
4868: {
4869: PetscSection section;
4873: DMClone(dm, cdm);
4874: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
4875: DMSetDefaultSection(*cdm, section);
4876: PetscSectionDestroy(§ion);
4877: return(0);
4878: }
4882: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
4883: {
4884: DM_Plex *mesh = (DM_Plex*) dm->data;
4888: if (section) *section = mesh->coneSection;
4889: return(0);
4890: }
4894: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
4895: {
4896: DM_Plex *mesh = (DM_Plex*) dm->data;
4900: if (section) *section = mesh->supportSection;
4901: return(0);
4902: }
4906: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
4907: {
4908: DM_Plex *mesh = (DM_Plex*) dm->data;
4912: if (cones) *cones = mesh->cones;
4913: return(0);
4914: }
4918: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
4919: {
4920: DM_Plex *mesh = (DM_Plex*) dm->data;
4924: if (coneOrientations) *coneOrientations = mesh->coneOrientations;
4925: return(0);
4926: }
4928: /******************************** FEM Support **********************************/
4932: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4933: {
4934: PetscScalar *array, *vArray;
4935: const PetscInt *cone, *coneO;
4936: PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0;
4937: PetscErrorCode ierr;
4940: PetscSectionGetChart(section, &pStart, &pEnd);
4941: DMPlexGetConeSize(dm, point, &numPoints);
4942: DMPlexGetCone(dm, point, &cone);
4943: DMPlexGetConeOrientation(dm, point, &coneO);
4944: if (!values || !*values) {
4945: if ((point >= pStart) && (point < pEnd)) {
4946: PetscInt dof;
4948: PetscSectionGetDof(section, point, &dof);
4949: size += dof;
4950: }
4951: for (p = 0; p < numPoints; ++p) {
4952: const PetscInt cp = cone[p];
4953: PetscInt dof;
4955: if ((cp < pStart) || (cp >= pEnd)) continue;
4956: PetscSectionGetDof(section, cp, &dof);
4957: size += dof;
4958: }
4959: if (!values) {
4960: if (csize) *csize = size;
4961: return(0);
4962: }
4963: DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
4964: } else {
4965: array = *values;
4966: }
4967: size = 0;
4968: VecGetArray(v, &vArray);
4969: if ((point >= pStart) && (point < pEnd)) {
4970: PetscInt dof, off, d;
4971: PetscScalar *varr;
4973: PetscSectionGetDof(section, point, &dof);
4974: PetscSectionGetOffset(section, point, &off);
4975: varr = &vArray[off];
4976: for (d = 0; d < dof; ++d, ++offset) {
4977: array[offset] = varr[d];
4978: }
4979: size += dof;
4980: }
4981: for (p = 0; p < numPoints; ++p) {
4982: const PetscInt cp = cone[p];
4983: PetscInt o = coneO[p];
4984: PetscInt dof, off, d;
4985: PetscScalar *varr;
4987: if ((cp < pStart) || (cp >= pEnd)) continue;
4988: PetscSectionGetDof(section, cp, &dof);
4989: PetscSectionGetOffset(section, cp, &off);
4990: varr = &vArray[off];
4991: if (o >= 0) {
4992: for (d = 0; d < dof; ++d, ++offset) {
4993: array[offset] = varr[d];
4994: }
4995: } else {
4996: for (d = dof-1; d >= 0; --d, ++offset) {
4997: array[offset] = varr[d];
4998: }
4999: }
5000: size += dof;
5001: }
5002: VecRestoreArray(v, &vArray);
5003: if (!*values) {
5004: if (csize) *csize = size;
5005: *values = array;
5006: } else {
5007: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
5008: *csize = size;
5009: }
5010: return(0);
5011: }
5015: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5016: {
5017: PetscInt offset = 0, p;
5021: *size = 0;
5022: for (p = 0; p < numPoints*2; p += 2) {
5023: const PetscInt point = points[p];
5024: const PetscInt o = points[p+1];
5025: PetscInt dof, off, d;
5026: const PetscScalar *varr;
5028: PetscSectionGetDof(section, point, &dof);
5029: PetscSectionGetOffset(section, point, &off);
5030: varr = &vArray[off];
5031: if (o >= 0) {
5032: for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
5033: } else {
5034: for (d = dof-1; d >= 0; --d, ++offset) array[offset] = varr[d];
5035: }
5036: }
5037: *size = offset;
5038: return(0);
5039: }
5043: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5044: {
5045: PetscInt offset = 0, f;
5049: *size = 0;
5050: for (f = 0; f < numFields; ++f) {
5051: PetscInt fcomp, p;
5053: PetscSectionGetFieldComponents(section, f, &fcomp);
5054: for (p = 0; p < numPoints*2; p += 2) {
5055: const PetscInt point = points[p];
5056: const PetscInt o = points[p+1];
5057: PetscInt fdof, foff, d, c;
5058: const PetscScalar *varr;
5060: PetscSectionGetFieldDof(section, point, f, &fdof);
5061: PetscSectionGetFieldOffset(section, point, f, &foff);
5062: varr = &vArray[foff];
5063: if (o >= 0) {
5064: for (d = 0; d < fdof; ++d, ++offset) array[offset] = varr[d];
5065: } else {
5066: for (d = fdof/fcomp-1; d >= 0; --d) {
5067: for (c = 0; c < fcomp; ++c, ++offset) {
5068: array[offset] = varr[d*fcomp+c];
5069: }
5070: }
5071: }
5072: }
5073: }
5074: *size = offset;
5075: return(0);
5076: }
5080: /*@C
5081: DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5083: Not collective
5085: Input Parameters:
5086: + dm - The DM
5087: . section - The section describing the layout in v, or NULL to use the default section
5088: . v - The local vector
5089: - point - The sieve point in the DM
5091: Output Parameters:
5092: + csize - The number of values in the closure, or NULL
5093: - values - The array of values, which is a borrowed array and should not be freed
5095: Fortran Notes:
5096: Since it returns an array, this routine is only available in Fortran 90, and you must
5097: include petsc.h90 in your code.
5099: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5101: Level: intermediate
5103: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5104: @*/
5105: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5106: {
5107: PetscSection clSection;
5108: IS clPoints;
5109: PetscScalar *array, *vArray;
5110: PetscInt *points = NULL;
5111: const PetscInt *clp;
5112: PetscInt depth, numFields, numPoints, size;
5113: PetscErrorCode ierr;
5117: if (!section) {DMGetDefaultSection(dm, §ion);}
5120: DMPlexGetDepth(dm, &depth);
5121: PetscSectionGetNumFields(section, &numFields);
5122: if (depth == 1 && numFields < 2) {
5123: DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
5124: return(0);
5125: }
5126: /* Get points */
5127: PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
5128: if (!clPoints) {
5129: PetscInt pStart, pEnd, p, q;
5131: PetscSectionGetChart(section, &pStart, &pEnd);
5132: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5133: /* Compress out points not in the section */
5134: for (p = 0, q = 0; p < numPoints*2; p += 2) {
5135: if ((points[p] >= pStart) && (points[p] < pEnd)) {
5136: points[q*2] = points[p];
5137: points[q*2+1] = points[p+1];
5138: ++q;
5139: }
5140: }
5141: numPoints = q;
5142: } else {
5143: PetscInt dof, off;
5145: PetscSectionGetDof(clSection, point, &dof);
5146: PetscSectionGetOffset(clSection, point, &off);
5147: ISGetIndices(clPoints, &clp);
5148: numPoints = dof/2;
5149: points = (PetscInt *) &clp[off];
5150: }
5151: /* Get array */
5152: if (!values || !*values) {
5153: PetscInt asize = 0, dof, p;
5155: for (p = 0; p < numPoints*2; p += 2) {
5156: PetscSectionGetDof(section, points[p], &dof);
5157: asize += dof;
5158: }
5159: if (!values) {
5160: if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
5161: else {ISRestoreIndices(clPoints, &clp);}
5162: if (csize) *csize = asize;
5163: return(0);
5164: }
5165: DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
5166: } else {
5167: array = *values;
5168: }
5169: VecGetArray(v, &vArray);
5170: /* Get values */
5171: if (numFields > 1) {DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, vArray, &size, array);}
5172: else {DMPlexVecGetClosure_Static(section, numPoints, points, vArray, &size, array);}
5173: /* Cleanup points */
5174: if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
5175: else {ISRestoreIndices(clPoints, &clp);}
5176: /* Cleanup array */
5177: VecRestoreArray(v, &vArray);
5178: if (!*values) {
5179: if (csize) *csize = size;
5180: *values = array;
5181: } else {
5182: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
5183: *csize = size;
5184: }
5185: return(0);
5186: }
5190: /*@C
5191: DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5193: Not collective
5195: Input Parameters:
5196: + dm - The DM
5197: . section - The section describing the layout in v, or NULL to use the default section
5198: . v - The local vector
5199: . point - The sieve point in the DM
5200: . csize - The number of values in the closure, or NULL
5201: - values - The array of values, which is a borrowed array and should not be freed
5203: Fortran Notes:
5204: Since it returns an array, this routine is only available in Fortran 90, and you must
5205: include petsc.h90 in your code.
5207: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5209: Level: intermediate
5211: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5212: @*/
5213: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5214: {
5215: PetscInt size = 0;
5219: /* Should work without recalculating size */
5220: DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
5221: return(0);
5222: }
5224: PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;}
5225: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;}
5229: PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5230: {
5231: PetscInt cdof; /* The number of constraints on this point */
5232: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5233: PetscScalar *a;
5234: PetscInt off, cind = 0, k;
5235: PetscErrorCode ierr;
5238: PetscSectionGetConstraintDof(section, point, &cdof);
5239: PetscSectionGetOffset(section, point, &off);
5240: a = &array[off];
5241: if (!cdof || setBC) {
5242: if (orientation >= 0) {
5243: for (k = 0; k < dof; ++k) {
5244: fuse(&a[k], values[k]);
5245: }
5246: } else {
5247: for (k = 0; k < dof; ++k) {
5248: fuse(&a[k], values[dof-k-1]);
5249: }
5250: }
5251: } else {
5252: PetscSectionGetConstraintIndices(section, point, &cdofs);
5253: if (orientation >= 0) {
5254: for (k = 0; k < dof; ++k) {
5255: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5256: fuse(&a[k], values[k]);
5257: }
5258: } else {
5259: for (k = 0; k < dof; ++k) {
5260: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5261: fuse(&a[k], values[dof-k-1]);
5262: }
5263: }
5264: }
5265: return(0);
5266: }
5270: PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5271: {
5272: PetscInt cdof; /* The number of constraints on this point */
5273: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5274: PetscScalar *a;
5275: PetscInt off, cind = 0, k;
5276: PetscErrorCode ierr;
5279: PetscSectionGetConstraintDof(section, point, &cdof);
5280: PetscSectionGetOffset(section, point, &off);
5281: a = &array[off];
5282: if (cdof) {
5283: PetscSectionGetConstraintIndices(section, point, &cdofs);
5284: if (orientation >= 0) {
5285: for (k = 0; k < dof; ++k) {
5286: if ((cind < cdof) && (k == cdofs[cind])) {
5287: fuse(&a[k], values[k]);
5288: ++cind;
5289: }
5290: }
5291: } else {
5292: for (k = 0; k < dof; ++k) {
5293: if ((cind < cdof) && (k == cdofs[cind])) {
5294: fuse(&a[k], values[dof-k-1]);
5295: ++cind;
5296: }
5297: }
5298: }
5299: }
5300: return(0);
5301: }
5305: PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscScalar values[], PetscInt *offset, PetscScalar array[])
5306: {
5307: PetscScalar *a;
5308: PetscInt fdof, foff, fcdof, foffset = *offset;
5309: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5310: PetscInt cind = 0, k, c;
5311: PetscErrorCode ierr;
5314: PetscSectionGetFieldDof(section, point, f, &fdof);
5315: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
5316: PetscSectionGetFieldOffset(section, point, f, &foff);
5317: a = &array[foff];
5318: if (!fcdof || setBC) {
5319: if (o >= 0) {
5320: for (k = 0; k < fdof; ++k) fuse(&a[k], values[foffset+k]);
5321: } else {
5322: for (k = fdof/fcomp-1; k >= 0; --k) {
5323: for (c = 0; c < fcomp; ++c) {
5324: fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
5325: }
5326: }
5327: }
5328: } else {
5329: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5330: if (o >= 0) {
5331: for (k = 0; k < fdof; ++k) {
5332: if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
5333: fuse(&a[k], values[foffset+k]);
5334: }
5335: } else {
5336: for (k = fdof/fcomp-1; k >= 0; --k) {
5337: for (c = 0; c < fcomp; ++c) {
5338: if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
5339: fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
5340: }
5341: }
5342: }
5343: }
5344: *offset += fdof;
5345: return(0);
5346: }
5350: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), const PetscScalar values[], PetscInt *offset, PetscScalar array[])
5351: {
5352: PetscScalar *a;
5353: PetscInt fdof, foff, fcdof, foffset = *offset;
5354: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5355: PetscInt cind = 0, k, c;
5356: PetscErrorCode ierr;
5359: PetscSectionGetFieldDof(section, point, f, &fdof);
5360: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
5361: PetscSectionGetFieldOffset(section, point, f, &foff);
5362: a = &array[foff];
5363: if (fcdof) {
5364: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5365: if (o >= 0) {
5366: for (k = 0; k < fdof; ++k) {
5367: if ((cind < fcdof) && (k == fcdofs[cind])) {
5368: fuse(&a[k], values[foffset+k]);
5369: ++cind;
5370: }
5371: }
5372: } else {
5373: for (k = fdof/fcomp-1; k >= 0; --k) {
5374: for (c = 0; c < fcomp; ++c) {
5375: if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
5376: fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
5377: ++cind;
5378: }
5379: }
5380: }
5381: }
5382: }
5383: *offset += fdof;
5384: return(0);
5385: }
5389: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5390: {
5391: PetscScalar *array;
5392: const PetscInt *cone, *coneO;
5393: PetscInt pStart, pEnd, p, numPoints, off, dof;
5394: PetscErrorCode ierr;
5397: PetscSectionGetChart(section, &pStart, &pEnd);
5398: DMPlexGetConeSize(dm, point, &numPoints);
5399: DMPlexGetCone(dm, point, &cone);
5400: DMPlexGetConeOrientation(dm, point, &coneO);
5401: VecGetArray(v, &array);
5402: for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
5403: const PetscInt cp = !p ? point : cone[p-1];
5404: const PetscInt o = !p ? 0 : coneO[p-1];
5406: if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
5407: PetscSectionGetDof(section, cp, &dof);
5408: /* ADD_VALUES */
5409: {
5410: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5411: PetscScalar *a;
5412: PetscInt cdof, coff, cind = 0, k;
5414: PetscSectionGetConstraintDof(section, cp, &cdof);
5415: PetscSectionGetOffset(section, cp, &coff);
5416: a = &array[coff];
5417: if (!cdof) {
5418: if (o >= 0) {
5419: for (k = 0; k < dof; ++k) {
5420: a[k] += values[off+k];
5421: }
5422: } else {
5423: for (k = 0; k < dof; ++k) {
5424: a[k] += values[off+dof-k-1];
5425: }
5426: }
5427: } else {
5428: PetscSectionGetConstraintIndices(section, cp, &cdofs);
5429: if (o >= 0) {
5430: for (k = 0; k < dof; ++k) {
5431: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5432: a[k] += values[off+k];
5433: }
5434: } else {
5435: for (k = 0; k < dof; ++k) {
5436: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5437: a[k] += values[off+dof-k-1];
5438: }
5439: }
5440: }
5441: }
5442: }
5443: VecRestoreArray(v, &array);
5444: return(0);
5445: }
5449: /*@C
5450: DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
5452: Not collective
5454: Input Parameters:
5455: + dm - The DM
5456: . section - The section describing the layout in v, or NULL to use the default section
5457: . v - The local vector
5458: . point - The sieve point in the DM
5459: . values - The array of values
5460: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5462: Fortran Notes:
5463: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5465: Level: intermediate
5467: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
5468: @*/
5469: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5470: {
5471: PetscSection clSection;
5472: IS clPoints;
5473: PetscScalar *array;
5474: PetscInt *points = NULL;
5475: const PetscInt *clp;
5476: PetscInt depth, numFields, numPoints, p;
5477: PetscErrorCode ierr;
5481: if (!section) {DMGetDefaultSection(dm, §ion);}
5484: DMPlexGetDepth(dm, &depth);
5485: PetscSectionGetNumFields(section, &numFields);
5486: if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
5487: DMPlexVecSetClosure_Static(dm, section, v, point, values, mode);
5488: return(0);
5489: }
5490: /* Get points */
5491: PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
5492: if (!clPoints) {
5493: PetscInt pStart, pEnd, q;
5495: PetscSectionGetChart(section, &pStart, &pEnd);
5496: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5497: /* Compress out points not in the section */
5498: for (p = 0, q = 0; p < numPoints*2; p += 2) {
5499: if ((points[p] >= pStart) && (points[p] < pEnd)) {
5500: points[q*2] = points[p];
5501: points[q*2+1] = points[p+1];
5502: ++q;
5503: }
5504: }
5505: numPoints = q;
5506: } else {
5507: PetscInt dof, off;
5509: PetscSectionGetDof(clSection, point, &dof);
5510: PetscSectionGetOffset(clSection, point, &off);
5511: ISGetIndices(clPoints, &clp);
5512: numPoints = dof/2;
5513: points = (PetscInt *) &clp[off];
5514: }
5515: /* Get array */
5516: VecGetArray(v, &array);
5517: /* Get values */
5518: if (numFields > 1) {
5519: PetscInt offset = 0, fcomp, f;
5520: for (f = 0; f < numFields; ++f) {
5521: PetscSectionGetFieldComponents(section, f, &fcomp);
5522: switch (mode) {
5523: case INSERT_VALUES:
5524: for (p = 0; p < numPoints*2; p += 2) {
5525: const PetscInt point = points[p];
5526: const PetscInt o = points[p+1];
5527: updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array);
5528: } break;
5529: case INSERT_ALL_VALUES:
5530: for (p = 0; p < numPoints*2; p += 2) {
5531: const PetscInt point = points[p];
5532: const PetscInt o = points[p+1];
5533: updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array);
5534: } break;
5535: case INSERT_BC_VALUES:
5536: for (p = 0; p < numPoints*2; p += 2) {
5537: const PetscInt point = points[p];
5538: const PetscInt o = points[p+1];
5539: updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array);
5540: } break;
5541: case ADD_VALUES:
5542: for (p = 0; p < numPoints*2; p += 2) {
5543: const PetscInt point = points[p];
5544: const PetscInt o = points[p+1];
5545: updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array);
5546: } break;
5547: case ADD_ALL_VALUES:
5548: for (p = 0; p < numPoints*2; p += 2) {
5549: const PetscInt point = points[p];
5550: const PetscInt o = points[p+1];
5551: updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array);
5552: } break;
5553: default:
5554: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5555: }
5556: }
5557: } else {
5558: PetscInt dof, off;
5560: switch (mode) {
5561: case INSERT_VALUES:
5562: for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5563: PetscInt o = points[p+1];
5564: PetscSectionGetDof(section, points[p], &dof);
5565: updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
5566: } break;
5567: case INSERT_ALL_VALUES:
5568: for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5569: PetscInt o = points[p+1];
5570: PetscSectionGetDof(section, points[p], &dof);
5571: updatePoint_private(section, points[p], dof, insert, PETSC_TRUE, o, &values[off], array);
5572: } break;
5573: case INSERT_BC_VALUES:
5574: for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5575: PetscInt o = points[p+1];
5576: PetscSectionGetDof(section, points[p], &dof);
5577: updatePointBC_private(section, points[p], dof, insert, o, &values[off], array);
5578: } break;
5579: case ADD_VALUES:
5580: for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5581: PetscInt o = points[p+1];
5582: PetscSectionGetDof(section, points[p], &dof);
5583: updatePoint_private(section, points[p], dof, add, PETSC_FALSE, o, &values[off], array);
5584: } break;
5585: case ADD_ALL_VALUES:
5586: for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5587: PetscInt o = points[p+1];
5588: PetscSectionGetDof(section, points[p], &dof);
5589: updatePoint_private(section, points[p], dof, add, PETSC_TRUE, o, &values[off], array);
5590: } break;
5591: default:
5592: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5593: }
5594: }
5595: /* Cleanup points */
5596: if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
5597: else {ISRestoreIndices(clPoints, &clp);}
5598: /* Cleanup array */
5599: VecRestoreArray(v, &array);
5600: return(0);
5601: }
5605: PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
5606: {
5607: PetscMPIInt rank;
5608: PetscInt i, j;
5612: MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
5613: PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);
5614: for (i = 0; i < numIndices; i++) {
5615: PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);
5616: }
5617: for (i = 0; i < numIndices; i++) {
5618: PetscViewerASCIIPrintf(viewer, "[%D]", rank);
5619: for (j = 0; j < numIndices; j++) {
5620: #if defined(PETSC_USE_COMPLEX)
5621: PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numIndices+j]), (double)PetscImaginaryPart(values[i*numIndices+j]));
5622: #else
5623: PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numIndices+j]);
5624: #endif
5625: }
5626: PetscViewerASCIIPrintf(viewer, "\n");
5627: }
5628: return(0);
5629: }
5633: /* . off - The global offset of this point */
5634: PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
5635: {
5636: PetscInt dof; /* The number of unknowns on this point */
5637: PetscInt cdof; /* The number of constraints on this point */
5638: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5639: PetscInt cind = 0, k;
5640: PetscErrorCode ierr;
5643: PetscSectionGetDof(section, point, &dof);
5644: PetscSectionGetConstraintDof(section, point, &cdof);
5645: if (!cdof || setBC) {
5646: if (orientation >= 0) {
5647: for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
5648: } else {
5649: for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
5650: }
5651: } else {
5652: PetscSectionGetConstraintIndices(section, point, &cdofs);
5653: if (orientation >= 0) {
5654: for (k = 0; k < dof; ++k) {
5655: if ((cind < cdof) && (k == cdofs[cind])) {
5656: /* Insert check for returning constrained indices */
5657: indices[*loff+k] = -(off+k+1);
5658: ++cind;
5659: } else {
5660: indices[*loff+k] = off+k-cind;
5661: }
5662: }
5663: } else {
5664: for (k = 0; k < dof; ++k) {
5665: if ((cind < cdof) && (k == cdofs[cind])) {
5666: /* Insert check for returning constrained indices */
5667: indices[*loff+dof-k-1] = -(off+k+1);
5668: ++cind;
5669: } else {
5670: indices[*loff+dof-k-1] = off+k-cind;
5671: }
5672: }
5673: }
5674: }
5675: *loff += dof;
5676: return(0);
5677: }
5681: /* . off - The global offset of this point */
5682: PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
5683: {
5684: PetscInt numFields, foff, f;
5688: PetscSectionGetNumFields(section, &numFields);
5689: for (f = 0, foff = 0; f < numFields; ++f) {
5690: PetscInt fdof, fcomp, cfdof;
5691: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5692: PetscInt cind = 0, k, c;
5694: PetscSectionGetFieldComponents(section, f, &fcomp);
5695: PetscSectionGetFieldDof(section, point, f, &fdof);
5696: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5697: if (!cfdof || setBC) {
5698: if (orientation >= 0) {
5699: for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
5700: } else {
5701: for (k = fdof/fcomp-1; k >= 0; --k) {
5702: for (c = 0; c < fcomp; ++c) {
5703: indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
5704: }
5705: }
5706: }
5707: } else {
5708: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5709: if (orientation >= 0) {
5710: for (k = 0; k < fdof; ++k) {
5711: if ((cind < cfdof) && (k == fcdofs[cind])) {
5712: indices[foffs[f]+k] = -(off+foff+k+1);
5713: ++cind;
5714: } else {
5715: indices[foffs[f]+k] = off+foff+k-cind;
5716: }
5717: }
5718: } else {
5719: for (k = fdof/fcomp-1; k >= 0; --k) {
5720: for (c = 0; c < fcomp; ++c) {
5721: if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
5722: indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
5723: ++cind;
5724: } else {
5725: indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
5726: }
5727: }
5728: }
5729: }
5730: }
5731: foff += fdof - cfdof;
5732: foffs[f] += fdof;
5733: }
5734: return(0);
5735: }
5739: /*@C
5740: DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5742: Not collective
5744: Input Parameters:
5745: + dm - The DM
5746: . section - The section describing the layout in v, or NULL to use the default section
5747: . globalSection - The section describing the layout in v, or NULL to use the default global section
5748: . A - The matrix
5749: . point - The sieve point in the DM
5750: . values - The array of values
5751: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5753: Fortran Notes:
5754: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5756: Level: intermediate
5758: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5759: @*/
5760: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5761: {
5762: DM_Plex *mesh = (DM_Plex*) dm->data;
5763: PetscSection clSection;
5764: IS clPoints;
5765: PetscInt *points = NULL;
5766: const PetscInt *clp;
5767: PetscInt *indices;
5768: PetscInt offsets[32];
5769: PetscInt numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
5770: PetscErrorCode ierr;
5774: if (!section) {DMGetDefaultSection(dm, §ion);}
5776: if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5779: PetscSectionGetNumFields(section, &numFields);
5780: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5781: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5782: PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
5783: if (!clPoints) {
5784: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5785: /* Compress out points not in the section */
5786: PetscSectionGetChart(section, &pStart, &pEnd);
5787: for (p = 0, q = 0; p < numPoints*2; p += 2) {
5788: if ((points[p] >= pStart) && (points[p] < pEnd)) {
5789: points[q*2] = points[p];
5790: points[q*2+1] = points[p+1];
5791: ++q;
5792: }
5793: }
5794: numPoints = q;
5795: } else {
5796: PetscInt dof, off;
5798: PetscSectionGetDof(clSection, point, &dof);
5799: numPoints = dof/2;
5800: PetscSectionGetOffset(clSection, point, &off);
5801: ISGetIndices(clPoints, &clp);
5802: points = (PetscInt *) &clp[off];
5803: }
5804: for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5805: PetscInt fdof;
5807: PetscSectionGetDof(section, points[p], &dof);
5808: for (f = 0; f < numFields; ++f) {
5809: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5810: offsets[f+1] += fdof;
5811: }
5812: numIndices += dof;
5813: }
5814: for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5816: if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
5817: DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5818: if (numFields) {
5819: for (p = 0; p < numPoints*2; p += 2) {
5820: PetscInt o = points[p+1];
5821: PetscSectionGetOffset(globalSection, points[p], &globalOff);
5822: indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
5823: }
5824: } else {
5825: for (p = 0, off = 0; p < numPoints*2; p += 2) {
5826: PetscInt o = points[p+1];
5827: PetscSectionGetOffset(globalSection, points[p], &globalOff);
5828: indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
5829: }
5830: }
5831: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);}
5832: MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5833: if (ierr) {
5834: PetscMPIInt rank;
5835: PetscErrorCode ierr2;
5837: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5838: ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5839: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
5840: ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5841:
5842: }
5843: if (!clPoints) {
5844: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5845: } else {
5846: ISRestoreIndices(clPoints, &clp);
5847: }
5848: DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5849: return(0);
5850: }
5854: /*@
5855: DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
5857: Input Parameter:
5858: . dm - The DMPlex object
5860: Output Parameters:
5861: + cMax - The first hybrid cell
5862: . cMax - The first hybrid face
5863: . cMax - The first hybrid edge
5864: - cMax - The first hybrid vertex
5866: Level: developer
5868: .seealso DMPlexCreateHybridMesh()
5869: @*/
5870: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5871: {
5872: DM_Plex *mesh = (DM_Plex*) dm->data;
5873: PetscInt dim;
5878: DMPlexGetDimension(dm, &dim);
5879: if (cMax) *cMax = mesh->hybridPointMax[dim];
5880: if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5881: if (eMax) *eMax = mesh->hybridPointMax[1];
5882: if (vMax) *vMax = mesh->hybridPointMax[0];
5883: return(0);
5884: }
5888: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5889: {
5890: DM_Plex *mesh = (DM_Plex*) dm->data;
5891: PetscInt dim;
5896: DMPlexGetDimension(dm, &dim);
5897: if (cMax >= 0) mesh->hybridPointMax[dim] = cMax;
5898: if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5899: if (eMax >= 0) mesh->hybridPointMax[1] = eMax;
5900: if (vMax >= 0) mesh->hybridPointMax[0] = vMax;
5901: return(0);
5902: }
5906: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5907: {
5908: DM_Plex *mesh = (DM_Plex*) dm->data;
5913: *cellHeight = mesh->vtkCellHeight;
5914: return(0);
5915: }
5919: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5920: {
5921: DM_Plex *mesh = (DM_Plex*) dm->data;
5925: mesh->vtkCellHeight = cellHeight;
5926: return(0);
5927: }
5931: /* We can easily have a form that takes an IS instead */
5932: PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
5933: {
5934: PetscSection section, globalSection;
5935: PetscInt *numbers, p;
5939: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
5940: PetscSectionSetChart(section, pStart, pEnd);
5941: for (p = pStart; p < pEnd; ++p) {
5942: PetscSectionSetDof(section, p, 1);
5943: }
5944: PetscSectionSetUp(section);
5945: PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);
5946: PetscMalloc1((pEnd - pStart), &numbers);
5947: for (p = pStart; p < pEnd; ++p) {
5948: PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5949: }
5950: ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5951: PetscSectionDestroy(§ion);
5952: PetscSectionDestroy(&globalSection);
5953: return(0);
5954: }
5958: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5959: {
5960: DM_Plex *mesh = (DM_Plex*) dm->data;
5961: PetscInt cellHeight, cStart, cEnd, cMax;
5966: if (!mesh->globalCellNumbers) {
5967: DMPlexGetVTKCellHeight(dm, &cellHeight);
5968: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5969: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5970: if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
5971: DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);
5972: }
5973: *globalCellNumbers = mesh->globalCellNumbers;
5974: return(0);
5975: }
5979: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5980: {
5981: DM_Plex *mesh = (DM_Plex*) dm->data;
5982: PetscInt vStart, vEnd, vMax;
5987: if (!mesh->globalVertexNumbers) {
5988: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5989: DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
5990: if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
5991: DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);
5992: }
5993: *globalVertexNumbers = mesh->globalVertexNumbers;
5994: return(0);
5995: }
6000: /*@C
6001: PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
6002: the local section and an SF describing the section point overlap.
6004: Input Parameters:
6005: + s - The PetscSection for the local field layout
6006: . sf - The SF describing parallel layout of the section points
6007: . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
6008: . label - The label specifying the points
6009: - labelValue - The label stratum specifying the points
6011: Output Parameter:
6012: . gsection - The PetscSection for the global field layout
6014: Note: This gives negative sizes and offsets to points not owned by this process
6016: Level: developer
6018: .seealso: PetscSectionCreate()
6019: @*/
6020: PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
6021: {
6022: PetscInt *neg = NULL, *tmpOff = NULL;
6023: PetscInt pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
6027: PetscSectionCreate(s->atlasLayout.comm, gsection);
6028: PetscSectionGetChart(s, &pStart, &pEnd);
6029: PetscSectionSetChart(*gsection, pStart, pEnd);
6030: PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);
6031: if (nroots >= 0) {
6032: if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
6033: PetscCalloc1(nroots, &neg);
6034: if (nroots > pEnd-pStart) {
6035: PetscCalloc1(nroots, &tmpOff);
6036: } else {
6037: tmpOff = &(*gsection)->atlasDof[-pStart];
6038: }
6039: }
6040: /* Mark ghost points with negative dof */
6041: for (p = pStart; p < pEnd; ++p) {
6042: PetscInt value;
6044: DMLabelGetValue(label, p, &value);
6045: if (value != labelValue) continue;
6046: PetscSectionGetDof(s, p, &dof);
6047: PetscSectionSetDof(*gsection, p, dof);
6048: PetscSectionGetConstraintDof(s, p, &cdof);
6049: if (!includeConstraints && cdof > 0) {PetscSectionSetConstraintDof(*gsection, p, cdof);}
6050: if (neg) neg[p] = -(dof+1);
6051: }
6052: PetscSectionSetUpBC(*gsection);
6053: if (nroots >= 0) {
6054: PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);
6055: PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);
6056: if (nroots > pEnd-pStart) {
6057: for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
6058: }
6059: }
6060: /* Calculate new sizes, get proccess offset, and calculate point offsets */
6061: for (p = 0, off = 0; p < pEnd-pStart; ++p) {
6062: cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
6063: (*gsection)->atlasOff[p] = off;
6064: off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
6065: }
6066: MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);
6067: globalOff -= off;
6068: for (p = 0, off = 0; p < pEnd-pStart; ++p) {
6069: (*gsection)->atlasOff[p] += globalOff;
6070: if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
6071: }
6072: /* Put in negative offsets for ghost points */
6073: if (nroots >= 0) {
6074: PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);
6075: PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);
6076: if (nroots > pEnd-pStart) {
6077: for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
6078: }
6079: }
6080: if (nroots >= 0 && nroots > pEnd-pStart) {PetscFree(tmpOff);}
6081: PetscFree(neg);
6082: return(0);
6083: }
6087: /*@
6088: DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6090: Input Parameters:
6091: + dm - The DMPlex object
6093: Note: This is a useful diagnostic when creating meshes programmatically.
6095: Level: developer
6097: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6098: @*/
6099: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6100: {
6101: PetscSection coneSection, supportSection;
6102: const PetscInt *cone, *support;
6103: PetscInt coneSize, c, supportSize, s;
6104: PetscInt pStart, pEnd, p, csize, ssize;
6105: PetscErrorCode ierr;
6109: DMPlexGetConeSection(dm, &coneSection);
6110: DMPlexGetSupportSection(dm, &supportSection);
6111: /* Check that point p is found in the support of its cone points, and vice versa */
6112: DMPlexGetChart(dm, &pStart, &pEnd);
6113: for (p = pStart; p < pEnd; ++p) {
6114: DMPlexGetConeSize(dm, p, &coneSize);
6115: DMPlexGetCone(dm, p, &cone);
6116: for (c = 0; c < coneSize; ++c) {
6117: DMPlexGetSupportSize(dm, cone[c], &supportSize);
6118: DMPlexGetSupport(dm, cone[c], &support);
6119: for (s = 0; s < supportSize; ++s) {
6120: if (support[s] == p) break;
6121: }
6122: if (s >= supportSize) {
6123: PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);
6124: for (s = 0; s < coneSize; ++s) {
6125: PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);
6126: }
6127: PetscPrintf(PETSC_COMM_SELF, "\n");
6128: PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);
6129: for (s = 0; s < supportSize; ++s) {
6130: PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);
6131: }
6132: PetscPrintf(PETSC_COMM_SELF, "\n");
6133: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
6134: }
6135: }
6136: DMPlexGetSupportSize(dm, p, &supportSize);
6137: DMPlexGetSupport(dm, p, &support);
6138: for (s = 0; s < supportSize; ++s) {
6139: DMPlexGetConeSize(dm, support[s], &coneSize);
6140: DMPlexGetCone(dm, support[s], &cone);
6141: for (c = 0; c < coneSize; ++c) {
6142: if (cone[c] == p) break;
6143: }
6144: if (c >= coneSize) {
6145: PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);
6146: for (c = 0; c < supportSize; ++c) {
6147: PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);
6148: }
6149: PetscPrintf(PETSC_COMM_SELF, "\n");
6150: PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);
6151: for (c = 0; c < coneSize; ++c) {
6152: PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);
6153: }
6154: PetscPrintf(PETSC_COMM_SELF, "\n");
6155: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
6156: }
6157: }
6158: }
6159: PetscSectionGetStorageSize(coneSection, &csize);
6160: PetscSectionGetStorageSize(supportSection, &ssize);
6161: if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
6162: return(0);
6163: }
6167: /*@
6168: DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6170: Input Parameters:
6171: + dm - The DMPlex object
6172: . isSimplex - Are the cells simplices or tensor products
6173: - cellHeight - Normally 0
6175: Note: This is a useful diagnostic when creating meshes programmatically.
6177: Level: developer
6179: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6180: @*/
6181: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6182: {
6183: PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6188: DMPlexGetDimension(dm, &dim);
6189: switch (dim) {
6190: case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6191: case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6192: case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6193: default:
6194: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
6195: }
6196: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6197: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6198: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6199: cMax = cMax >= 0 ? cMax : cEnd;
6200: for (c = cStart; c < cMax; ++c) {
6201: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6203: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6204: for (cl = 0; cl < closureSize*2; cl += 2) {
6205: const PetscInt p = closure[cl];
6206: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6207: }
6208: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6209: if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d vertices != %d", c, coneSize, numCorners);
6210: }
6211: for (c = cMax; c < cEnd; ++c) {
6212: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6214: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6215: for (cl = 0; cl < closureSize*2; cl += 2) {
6216: const PetscInt p = closure[cl];
6217: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6218: }
6219: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6220: if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has %d vertices > %d", c, coneSize, numHybridCorners);
6221: }
6222: return(0);
6223: }
6227: /*@
6228: DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6230: Input Parameters:
6231: + dm - The DMPlex object
6232: . isSimplex - Are the cells simplices or tensor products
6233: - cellHeight - Normally 0
6235: Note: This is a useful diagnostic when creating meshes programmatically.
6237: Level: developer
6239: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6240: @*/
6241: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6242: {
6243: PetscInt pMax[4];
6244: PetscInt dim, vStart, vEnd, cStart, cEnd, c, h;
6249: DMPlexGetDimension(dm, &dim);
6250: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6251: DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6252: for (h = cellHeight; h < dim; ++h) {
6253: DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6254: for (c = cStart; c < cEnd; ++c) {
6255: const PetscInt *cone, *ornt, *faces;
6256: PetscInt numFaces, faceSize, coneSize,f;
6257: PetscInt *closure = NULL, closureSize, cl, numCorners = 0;
6259: if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6260: DMPlexGetConeSize(dm, c, &coneSize);
6261: DMPlexGetCone(dm, c, &cone);
6262: DMPlexGetConeOrientation(dm, c, &ornt);
6263: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6264: for (cl = 0; cl < closureSize*2; cl += 2) {
6265: const PetscInt p = closure[cl];
6266: if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6267: }
6268: DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6269: if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
6270: for (f = 0; f < numFaces; ++f) {
6271: PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6273: DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6274: for (cl = 0; cl < fclosureSize*2; cl += 2) {
6275: const PetscInt p = fclosure[cl];
6276: if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6277: }
6278: if (fnumCorners != faceSize) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d has %d vertices but should have %d", cone[f], f, c, fnumCorners, faceSize);
6279: for (v = 0; v < fnumCorners; ++v) {
6280: if (fclosure[v] != faces[f*faceSize+v]) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d vertex %d, %d != %d", cone[f], f, c, v, fclosure[v], faces[f*faceSize+v]);
6281: }
6282: DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6283: }
6284: DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6285: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6286: }
6287: }
6288: return(0);
6289: }