Actual source code: plex.c
petsc-3.12.0 2019-09-29
1: #include <petsc/private/dmpleximpl.h>
2: #include <petsc/private/isimpl.h>
3: #include <petsc/private/vecimpl.h>
4: #include <petsc/private/glvisvecimpl.h>
5: #include <petscsf.h>
6: #include <petscds.h>
7: #include <petscdraw.h>
8: #include <petscdmfield.h>
10: /* Logging support */
11: PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF;
13: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
15: /*@
16: DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells.
17: 3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D.
19: Collective
21: Input Parameters:
22: . dm - The DMPlex object
24: Output Parameters:
25: . dmRefined - The refined DMPlex object
27: Note: Returns NULL if the mesh is already a tensor product mesh.
29: Level: intermediate
31: .seealso: DMPlexCreate(), DMPlexSetRefinementUniform()
32: @*/
33: PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined)
34: {
35: PetscInt dim, cMax, fMax, cStart, cEnd, coneSize;
36: CellRefiner cellRefiner;
37: PetscBool lop, allnoop, localized;
38: PetscErrorCode ierr;
43: DMGetDimension(dm, &dim);
44: DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
45: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
46: if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
47: else {
48: DMPlexGetConeSize(dm,cStart,&coneSize);
49: switch (dim) {
50: case 1:
51: cellRefiner = REFINER_NOOP;
52: break;
53: case 2:
54: switch (coneSize) {
55: case 3:
56: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
57: else cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
58: break;
59: case 4:
60: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
61: else cellRefiner = REFINER_NOOP;
62: break;
63: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
64: }
65: break;
66: case 3:
67: switch (coneSize) {
68: case 4:
69: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
70: else cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
71: break;
72: case 5:
73: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
74: else cellRefiner = REFINER_NOOP;
75: break;
76: case 6:
77: if (cMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Simplex2Tensor in 3D with Hybrid mesh not yet done");
78: cellRefiner = REFINER_NOOP;
79: break;
80: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
81: }
82: break;
83: default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
84: }
85: }
86: /* return if we don't need to refine */
87: lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
88: MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
89: if (allnoop) {
90: *dmRefined = NULL;
91: return(0);
92: }
93: DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
94: DMCopyBoundary(dm, *dmRefined);
95: DMGetCoordinatesLocalized(dm, &localized);
96: if (localized) {
97: DMLocalizeCoordinates(*dmRefined);
98: }
99: return(0);
100: }
102: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
103: {
104: PetscInt dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior;
105: PetscInt vcdof[2] = {0,0}, globalvcdof[2];
109: *ft = PETSC_VTK_POINT_FIELD;
110: DMGetDimension(dm, &dim);
111: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
112: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
113: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
114: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
115: PetscSectionGetChart(section, &pStart, &pEnd);
116: if (field >= 0) {
117: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);}
118: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);}
119: } else {
120: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vcdof[0]);}
121: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &vcdof[1]);}
122: }
123: MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
124: if (globalvcdof[0]) {
125: *sStart = vStart;
126: *sEnd = vEnd;
127: if (globalvcdof[0] == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
128: else *ft = PETSC_VTK_POINT_FIELD;
129: } else if (globalvcdof[1]) {
130: *sStart = cStart;
131: *sEnd = cEnd;
132: if (globalvcdof[1] == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
133: else *ft = PETSC_VTK_CELL_FIELD;
134: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
135: return(0);
136: }
138: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
139: {
140: DM dm;
141: PetscSection s;
142: PetscDraw draw, popup;
143: DM cdm;
144: PetscSection coordSection;
145: Vec coordinates;
146: const PetscScalar *coords, *array;
147: PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
148: PetscReal vbound[2], time;
149: PetscBool isnull, flg;
150: PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
151: const char *name;
152: char title[PETSC_MAX_PATH_LEN];
153: PetscErrorCode ierr;
156: PetscViewerDrawGetDraw(viewer, 0, &draw);
157: PetscDrawIsNull(draw, &isnull);
158: if (isnull) return(0);
160: VecGetDM(v, &dm);
161: DMGetCoordinateDim(dm, &dim);
162: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
163: DMGetLocalSection(dm, &s);
164: PetscSectionGetNumFields(s, &Nf);
165: DMGetCoarsenLevel(dm, &level);
166: DMGetCoordinateDM(dm, &cdm);
167: DMGetLocalSection(cdm, &coordSection);
168: DMGetCoordinatesLocal(dm, &coordinates);
169: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
170: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
172: PetscObjectGetName((PetscObject) v, &name);
173: DMGetOutputSequenceNumber(dm, &step, &time);
175: VecGetLocalSize(coordinates, &N);
176: VecGetArrayRead(coordinates, &coords);
177: for (c = 0; c < N; c += dim) {
178: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
179: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
180: }
181: VecRestoreArrayRead(coordinates, &coords);
182: PetscDrawClear(draw);
184: /* Could implement something like DMDASelectFields() */
185: for (f = 0; f < Nf; ++f) {
186: DM fdm = dm;
187: Vec fv = v;
188: IS fis;
189: char prefix[PETSC_MAX_PATH_LEN];
190: const char *fname;
192: PetscSectionGetFieldComponents(s, f, &Nc);
193: PetscSectionGetFieldName(s, f, &fname);
195: if (v->hdr.prefix) {PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));}
196: else {prefix[0] = '\0';}
197: if (Nf > 1) {
198: DMCreateSubDM(dm, 1, &f, &fis, &fdm);
199: VecGetSubVector(v, fis, &fv);
200: PetscStrlcat(prefix, fname,sizeof(prefix));
201: PetscStrlcat(prefix, "_",sizeof(prefix));
202: }
203: for (comp = 0; comp < Nc; ++comp, ++w) {
204: PetscInt nmax = 2;
206: PetscViewerDrawGetDraw(viewer, w, &draw);
207: if (Nc > 1) {PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);}
208: else {PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);}
209: PetscDrawSetTitle(draw, title);
211: /* TODO Get max and min only for this component */
212: PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
213: if (!flg) {
214: VecMin(fv, NULL, &vbound[0]);
215: VecMax(fv, NULL, &vbound[1]);
216: if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
217: }
218: PetscDrawGetPopup(draw, &popup);
219: PetscDrawScalePopup(popup, vbound[0], vbound[1]);
220: PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
222: VecGetArrayRead(fv, &array);
223: for (c = cStart; c < cEnd; ++c) {
224: PetscScalar *coords = NULL, *a = NULL;
225: PetscInt numCoords, color[4] = {-1,-1,-1,-1};
227: DMPlexPointLocalRead(fdm, c, array, &a);
228: if (a) {
229: color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
230: color[1] = color[2] = color[3] = color[0];
231: } else {
232: PetscScalar *vals = NULL;
233: PetscInt numVals, va;
235: DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
236: if (numVals % Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %D does not divide the number of values in the closure %D", Nc, numVals);
237: switch (numVals/Nc) {
238: case 3: /* P1 Triangle */
239: case 4: /* P1 Quadrangle */
240: for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
241: break;
242: case 6: /* P2 Triangle */
243: case 8: /* P2 Quadrangle */
244: for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
245: break;
246: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
247: }
248: DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
249: }
250: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
251: switch (numCoords) {
252: case 6:
253: PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
254: break;
255: case 8:
256: PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
257: PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0]);
258: break;
259: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
260: }
261: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
262: }
263: VecRestoreArrayRead(fv, &array);
264: PetscDrawFlush(draw);
265: PetscDrawPause(draw);
266: PetscDrawSave(draw);
267: }
268: if (Nf > 1) {
269: VecRestoreSubVector(v, fis, &fv);
270: ISDestroy(&fis);
271: DMDestroy(&fdm);
272: }
273: }
274: return(0);
275: }
277: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
278: {
279: DM dm;
280: Vec locv;
281: const char *name;
282: PetscSection section;
283: PetscInt pStart, pEnd;
284: PetscViewerVTKFieldType ft;
285: PetscErrorCode ierr;
288: VecGetDM(v, &dm);
289: DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
290: PetscObjectGetName((PetscObject) v, &name);
291: PetscObjectSetName((PetscObject) locv, name);
292: VecCopy(v, locv);
293: DMGetLocalSection(dm, §ion);
294: DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
295: PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, PETSC_TRUE,(PetscObject) locv);
296: return(0);
297: }
299: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
300: {
301: DM dm;
302: PetscBool isvtk, ishdf5, isdraw, isglvis;
306: VecGetDM(v, &dm);
307: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
308: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
309: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
310: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
311: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
312: if (isvtk || ishdf5 || isdraw || isglvis) {
313: PetscInt i,numFields;
314: PetscObject fe;
315: PetscBool fem = PETSC_FALSE;
316: Vec locv = v;
317: const char *name;
318: PetscInt step;
319: PetscReal time;
321: DMGetNumFields(dm, &numFields);
322: for (i=0; i<numFields; i++) {
323: DMGetField(dm, i, NULL, &fe);
324: if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
325: }
326: if (fem) {
327: DMGetLocalVector(dm, &locv);
328: PetscObjectGetName((PetscObject) v, &name);
329: PetscObjectSetName((PetscObject) locv, name);
330: VecCopy(v, locv);
331: DMGetOutputSequenceNumber(dm, NULL, &time);
332: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
333: }
334: if (isvtk) {
335: VecView_Plex_Local_VTK(locv, viewer);
336: } else if (ishdf5) {
337: #if defined(PETSC_HAVE_HDF5)
338: VecView_Plex_Local_HDF5_Internal(locv, viewer);
339: #else
340: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
341: #endif
342: } else if (isdraw) {
343: VecView_Plex_Local_Draw(locv, viewer);
344: } else if (isglvis) {
345: DMGetOutputSequenceNumber(dm, &step, NULL);
346: PetscViewerGLVisSetSnapId(viewer, step);
347: VecView_GLVis(locv, viewer);
348: }
349: if (fem) {DMRestoreLocalVector(dm, &locv);}
350: } else {
351: PetscBool isseq;
353: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
354: if (isseq) {VecView_Seq(v, viewer);}
355: else {VecView_MPI(v, viewer);}
356: }
357: return(0);
358: }
360: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
361: {
362: DM dm;
363: PetscBool isvtk, ishdf5, isdraw, isglvis;
367: VecGetDM(v, &dm);
368: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
369: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
370: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
371: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
372: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
373: if (isvtk || isdraw || isglvis) {
374: Vec locv;
375: const char *name;
377: DMGetLocalVector(dm, &locv);
378: PetscObjectGetName((PetscObject) v, &name);
379: PetscObjectSetName((PetscObject) locv, name);
380: DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
381: DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
382: VecView_Plex_Local(locv, viewer);
383: DMRestoreLocalVector(dm, &locv);
384: } else if (ishdf5) {
385: #if defined(PETSC_HAVE_HDF5)
386: VecView_Plex_HDF5_Internal(v, viewer);
387: #else
388: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
389: #endif
390: } else {
391: PetscBool isseq;
393: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
394: if (isseq) {VecView_Seq(v, viewer);}
395: else {VecView_MPI(v, viewer);}
396: }
397: return(0);
398: }
400: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
401: {
402: DM dm;
403: MPI_Comm comm;
404: PetscViewerFormat format;
405: Vec v;
406: PetscBool isvtk, ishdf5;
407: PetscErrorCode ierr;
410: VecGetDM(originalv, &dm);
411: PetscObjectGetComm((PetscObject) originalv, &comm);
412: if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
413: PetscViewerGetFormat(viewer, &format);
414: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
415: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
416: if (format == PETSC_VIEWER_NATIVE) {
417: /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
418: /* this need a better fix */
419: if (dm->useNatural) {
420: if (dm->sfNatural) {
421: const char *vecname;
422: PetscInt n, nroots;
424: VecGetLocalSize(originalv, &n);
425: PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
426: if (n == nroots) {
427: DMGetGlobalVector(dm, &v);
428: DMPlexGlobalToNaturalBegin(dm, originalv, v);
429: DMPlexGlobalToNaturalEnd(dm, originalv, v);
430: PetscObjectGetName((PetscObject) originalv, &vecname);
431: PetscObjectSetName((PetscObject) v, vecname);
432: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
433: } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
434: } else v = originalv;
435: } else v = originalv;
437: if (ishdf5) {
438: #if defined(PETSC_HAVE_HDF5)
439: VecView_Plex_HDF5_Native_Internal(v, viewer);
440: #else
441: SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
442: #endif
443: } else if (isvtk) {
444: SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
445: } else {
446: PetscBool isseq;
448: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
449: if (isseq) {VecView_Seq(v, viewer);}
450: else {VecView_MPI(v, viewer);}
451: }
452: if (v != originalv) {DMRestoreGlobalVector(dm, &v);}
453: return(0);
454: }
456: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
457: {
458: DM dm;
459: PetscBool ishdf5;
463: VecGetDM(v, &dm);
464: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
465: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
466: if (ishdf5) {
467: DM dmBC;
468: Vec gv;
469: const char *name;
471: DMGetOutputDM(dm, &dmBC);
472: DMGetGlobalVector(dmBC, &gv);
473: PetscObjectGetName((PetscObject) v, &name);
474: PetscObjectSetName((PetscObject) gv, name);
475: VecLoad_Default(gv, viewer);
476: DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
477: DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
478: DMRestoreGlobalVector(dmBC, &gv);
479: } else {
480: VecLoad_Default(v, viewer);
481: }
482: return(0);
483: }
485: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
486: {
487: DM dm;
488: PetscBool ishdf5;
492: VecGetDM(v, &dm);
493: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
494: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
495: if (ishdf5) {
496: #if defined(PETSC_HAVE_HDF5)
497: VecLoad_Plex_HDF5_Internal(v, viewer);
498: #else
499: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
500: #endif
501: } else {
502: VecLoad_Default(v, viewer);
503: }
504: return(0);
505: }
507: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
508: {
509: DM dm;
510: PetscViewerFormat format;
511: PetscBool ishdf5;
512: PetscErrorCode ierr;
515: VecGetDM(originalv, &dm);
516: if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
517: PetscViewerGetFormat(viewer, &format);
518: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
519: if (format == PETSC_VIEWER_NATIVE) {
520: if (dm->useNatural) {
521: if (dm->sfNatural) {
522: if (ishdf5) {
523: #if defined(PETSC_HAVE_HDF5)
524: Vec v;
525: const char *vecname;
527: DMGetGlobalVector(dm, &v);
528: PetscObjectGetName((PetscObject) originalv, &vecname);
529: PetscObjectSetName((PetscObject) v, vecname);
530: VecLoad_Plex_HDF5_Native_Internal(v, viewer);
531: DMPlexNaturalToGlobalBegin(dm, v, originalv);
532: DMPlexNaturalToGlobalEnd(dm, v, originalv);
533: DMRestoreGlobalVector(dm, &v);
534: #else
535: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
536: #endif
537: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
538: }
539: } else {
540: VecLoad_Default(originalv, viewer);
541: }
542: }
543: return(0);
544: }
546: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
547: {
548: PetscSection coordSection;
549: Vec coordinates;
550: DMLabel depthLabel;
551: const char *name[4];
552: const PetscScalar *a;
553: PetscInt dim, pStart, pEnd, cStart, cEnd, c;
554: PetscErrorCode ierr;
557: DMGetDimension(dm, &dim);
558: DMGetCoordinatesLocal(dm, &coordinates);
559: DMGetCoordinateSection(dm, &coordSection);
560: DMPlexGetDepthLabel(dm, &depthLabel);
561: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
562: PetscSectionGetChart(coordSection, &pStart, &pEnd);
563: VecGetArrayRead(coordinates, &a);
564: name[0] = "vertex";
565: name[1] = "edge";
566: name[dim-1] = "face";
567: name[dim] = "cell";
568: for (c = cStart; c < cEnd; ++c) {
569: PetscInt *closure = NULL;
570: PetscInt closureSize, cl;
572: PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);
573: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
574: PetscViewerASCIIPushTab(viewer);
575: for (cl = 0; cl < closureSize*2; cl += 2) {
576: PetscInt point = closure[cl], depth, dof, off, d, p;
578: if ((point < pStart) || (point >= pEnd)) continue;
579: PetscSectionGetDof(coordSection, point, &dof);
580: if (!dof) continue;
581: DMLabelGetValue(depthLabel, point, &depth);
582: PetscSectionGetOffset(coordSection, point, &off);
583: PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
584: for (p = 0; p < dof/dim; ++p) {
585: PetscViewerASCIIPrintf(viewer, " (");
586: for (d = 0; d < dim; ++d) {
587: if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
588: PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));
589: }
590: PetscViewerASCIIPrintf(viewer, ")");
591: }
592: PetscViewerASCIIPrintf(viewer, "\n");
593: }
594: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
595: PetscViewerASCIIPopTab(viewer);
596: }
597: VecRestoreArrayRead(coordinates, &a);
598: return(0);
599: }
601: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
602: {
603: DM_Plex *mesh = (DM_Plex*) dm->data;
604: DM cdm;
605: DMLabel markers;
606: PetscSection coordSection;
607: Vec coordinates;
608: PetscViewerFormat format;
609: PetscErrorCode ierr;
612: DMGetCoordinateDM(dm, &cdm);
613: DMGetLocalSection(cdm, &coordSection);
614: DMGetCoordinatesLocal(dm, &coordinates);
615: PetscViewerGetFormat(viewer, &format);
616: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
617: const char *name;
618: PetscInt dim, cellHeight, maxConeSize, maxSupportSize;
619: PetscInt pStart, pEnd, p;
620: PetscMPIInt rank, size;
622: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
623: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
624: PetscObjectGetName((PetscObject) dm, &name);
625: DMPlexGetChart(dm, &pStart, &pEnd);
626: DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
627: DMGetDimension(dm, &dim);
628: DMPlexGetVTKCellHeight(dm, &cellHeight);
629: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
630: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
631: if (cellHeight) {PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);}
632: PetscViewerASCIIPrintf(viewer, "Supports:\n", name);
633: PetscViewerASCIIPushSynchronized(viewer);
634: PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);
635: for (p = pStart; p < pEnd; ++p) {
636: PetscInt dof, off, s;
638: PetscSectionGetDof(mesh->supportSection, p, &dof);
639: PetscSectionGetOffset(mesh->supportSection, p, &off);
640: for (s = off; s < off+dof; ++s) {
641: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
642: }
643: }
644: PetscViewerFlush(viewer);
645: PetscViewerASCIIPrintf(viewer, "Cones:\n", name);
646: PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);
647: for (p = pStart; p < pEnd; ++p) {
648: PetscInt dof, off, c;
650: PetscSectionGetDof(mesh->coneSection, p, &dof);
651: PetscSectionGetOffset(mesh->coneSection, p, &off);
652: for (c = off; c < off+dof; ++c) {
653: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
654: }
655: }
656: PetscViewerFlush(viewer);
657: PetscViewerASCIIPopSynchronized(viewer);
658: if (coordSection && coordinates) {
659: PetscSectionVecView(coordSection, coordinates, viewer);
660: }
661: DMGetLabel(dm, "marker", &markers);
662: if (markers) {DMLabelView(markers,viewer);}
663: if (size > 1) {
664: PetscSF sf;
666: DMGetPointSF(dm, &sf);
667: PetscSFView(sf, viewer);
668: }
669: PetscViewerFlush(viewer);
670: } else if (format == PETSC_VIEWER_ASCII_LATEX) {
671: const char *name, *color;
672: const char *defcolors[3] = {"gray", "orange", "green"};
673: const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
674: char lname[PETSC_MAX_PATH_LEN];
675: PetscReal scale = 2.0;
676: PetscReal tikzscale = 1.0;
677: PetscBool useNumbers = PETSC_TRUE, useLabels, useColors;
678: double tcoords[3];
679: PetscScalar *coords;
680: PetscInt numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
681: PetscMPIInt rank, size;
682: char **names, **colors, **lcolors;
683: PetscBool plotEdges, flg, lflg;
684: PetscBT wp = NULL;
685: PetscInt pEnd, pStart;
687: DMGetDimension(dm, &dim);
688: DMPlexGetDepth(dm, &depth);
689: DMGetNumLabels(dm, &numLabels);
690: numLabels = PetscMax(numLabels, 10);
691: numColors = 10;
692: numLColors = 10;
693: PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
694: PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
695: PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);
696: PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
697: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
698: if (!useLabels) numLabels = 0;
699: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
700: if (!useColors) {
701: numColors = 3;
702: for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
703: }
704: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
705: if (!useColors) {
706: numLColors = 4;
707: for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
708: }
709: PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, PETSC_MAX_PATH_LEN, &lflg);
710: plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
711: PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);
712: if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
713: if (depth < dim) plotEdges = PETSC_FALSE;
715: /* filter points with labelvalue != labeldefaultvalue */
716: DMPlexGetChart(dm, &pStart, &pEnd);
717: if (lflg) {
718: DMLabel lbl;
720: DMGetLabel(dm, lname, &lbl);
721: if (lbl) {
722: PetscInt val, defval;
724: DMLabelGetDefaultValue(lbl, &defval);
725: PetscBTCreate(pEnd-pStart, &wp);
726: for (c = pStart; c < pEnd; c++) {
727: PetscInt *closure = NULL;
728: PetscInt closureSize;
730: DMLabelGetValue(lbl, c, &val);
731: if (val == defval) continue;
733: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
734: for (p = 0; p < closureSize*2; p += 2) {
735: PetscBTSet(wp, closure[p] - pStart);
736: }
737: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
738: }
739: }
740: }
742: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
743: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
744: PetscObjectGetName((PetscObject) dm, &name);
745: PetscViewerASCIIPrintf(viewer, "\
746: \\documentclass[tikz]{standalone}\n\n\
747: \\usepackage{pgflibraryshapes}\n\
748: \\usetikzlibrary{backgrounds}\n\
749: \\usetikzlibrary{arrows}\n\
750: \\begin{document}\n");
751: if (size > 1) {
752: PetscViewerASCIIPrintf(viewer, "%s for process ", name);
753: for (p = 0; p < size; ++p) {
754: if (p > 0 && p == size-1) {
755: PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
756: } else if (p > 0) {
757: PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
758: }
759: PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
760: }
761: PetscViewerASCIIPrintf(viewer, ".\n\n\n");
762: }
763: PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);
765: /* Plot vertices */
766: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
767: VecGetArray(coordinates, &coords);
768: PetscViewerASCIIPushSynchronized(viewer);
769: for (v = vStart; v < vEnd; ++v) {
770: PetscInt off, dof, d;
771: PetscBool isLabeled = PETSC_FALSE;
773: if (wp && !PetscBTLookup(wp,v - pStart)) continue;
774: PetscSectionGetDof(coordSection, v, &dof);
775: PetscSectionGetOffset(coordSection, v, &off);
776: PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
777: if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
778: for (d = 0; d < dof; ++d) {
779: tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
780: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
781: }
782: /* Rotate coordinates since PGF makes z point out of the page instead of up */
783: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
784: for (d = 0; d < dof; ++d) {
785: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
786: PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);
787: }
788: color = colors[rank%numColors];
789: for (l = 0; l < numLabels; ++l) {
790: PetscInt val;
791: DMGetLabelValue(dm, names[l], v, &val);
792: if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
793: }
794: if (useNumbers) {
795: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
796: } else {
797: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
798: }
799: }
800: VecRestoreArray(coordinates, &coords);
801: PetscViewerFlush(viewer);
802: /* Plot cells */
803: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
804: DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
805: if (dim == 3 || !useNumbers) {
806: for (e = eStart; e < eEnd; ++e) {
807: const PetscInt *cone;
809: if (wp && !PetscBTLookup(wp,e - pStart)) continue;
810: color = colors[rank%numColors];
811: for (l = 0; l < numLabels; ++l) {
812: PetscInt val;
813: DMGetLabelValue(dm, names[l], e, &val);
814: if (val >= 0) {color = lcolors[l%numLColors]; break;}
815: }
816: DMPlexGetCone(dm, e, &cone);
817: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
818: }
819: } else {
820: for (c = cStart; c < cEnd; ++c) {
821: PetscInt *closure = NULL;
822: PetscInt closureSize, firstPoint = -1;
824: if (wp && !PetscBTLookup(wp,c - pStart)) continue;
825: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
826: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
827: for (p = 0; p < closureSize*2; p += 2) {
828: const PetscInt point = closure[p];
830: if ((point < vStart) || (point >= vEnd)) continue;
831: if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
832: PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
833: if (firstPoint < 0) firstPoint = point;
834: }
835: /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
836: PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
837: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
838: }
839: }
840: VecGetArray(coordinates, &coords);
841: for (c = cStart; c < cEnd; ++c) {
842: double ccoords[3] = {0.0, 0.0, 0.0};
843: PetscBool isLabeled = PETSC_FALSE;
844: PetscInt *closure = NULL;
845: PetscInt closureSize, dof, d, n = 0;
847: if (wp && !PetscBTLookup(wp,c - pStart)) continue;
848: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
849: PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
850: for (p = 0; p < closureSize*2; p += 2) {
851: const PetscInt point = closure[p];
852: PetscInt off;
854: if ((point < vStart) || (point >= vEnd)) continue;
855: PetscSectionGetDof(coordSection, point, &dof);
856: PetscSectionGetOffset(coordSection, point, &off);
857: for (d = 0; d < dof; ++d) {
858: tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
859: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
860: }
861: /* Rotate coordinates since PGF makes z point out of the page instead of up */
862: if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
863: for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
864: ++n;
865: }
866: for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
867: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
868: for (d = 0; d < dof; ++d) {
869: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
870: PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);
871: }
872: color = colors[rank%numColors];
873: for (l = 0; l < numLabels; ++l) {
874: PetscInt val;
875: DMGetLabelValue(dm, names[l], c, &val);
876: if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
877: }
878: if (useNumbers) {
879: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);
880: } else {
881: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);
882: }
883: }
884: VecRestoreArray(coordinates, &coords);
885: /* Plot edges */
886: if (plotEdges) {
887: VecGetArray(coordinates, &coords);
888: PetscViewerASCIIPrintf(viewer, "\\path\n");
889: for (e = eStart; e < eEnd; ++e) {
890: const PetscInt *cone;
891: PetscInt coneSize, offA, offB, dof, d;
893: if (wp && !PetscBTLookup(wp,e - pStart)) continue;
894: DMPlexGetConeSize(dm, e, &coneSize);
895: if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
896: DMPlexGetCone(dm, e, &cone);
897: PetscSectionGetDof(coordSection, cone[0], &dof);
898: PetscSectionGetOffset(coordSection, cone[0], &offA);
899: PetscSectionGetOffset(coordSection, cone[1], &offB);
900: PetscViewerASCIISynchronizedPrintf(viewer, "(");
901: for (d = 0; d < dof; ++d) {
902: tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
903: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
904: }
905: /* Rotate coordinates since PGF makes z point out of the page instead of up */
906: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
907: for (d = 0; d < dof; ++d) {
908: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
909: PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
910: }
911: color = colors[rank%numColors];
912: for (l = 0; l < numLabels; ++l) {
913: PetscInt val;
914: DMGetLabelValue(dm, names[l], v, &val);
915: if (val >= 0) {color = lcolors[l%numLColors]; break;}
916: }
917: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
918: }
919: VecRestoreArray(coordinates, &coords);
920: PetscViewerFlush(viewer);
921: PetscViewerASCIIPrintf(viewer, "(0,0);\n");
922: }
923: PetscViewerFlush(viewer);
924: PetscViewerASCIIPopSynchronized(viewer);
925: PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
926: PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
927: for (l = 0; l < numLabels; ++l) {PetscFree(names[l]);}
928: for (c = 0; c < numColors; ++c) {PetscFree(colors[c]);}
929: for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
930: PetscFree3(names, colors, lcolors);
931: PetscBTDestroy(&wp);
932: } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
933: Vec cown,acown;
934: VecScatter sct;
935: ISLocalToGlobalMapping g2l;
936: IS gid,acis;
937: MPI_Comm comm,ncomm = MPI_COMM_NULL;
938: MPI_Group ggroup,ngroup;
939: PetscScalar *array,nid;
940: const PetscInt *idxs;
941: PetscInt *idxs2,*start,*adjacency,*work;
942: PetscInt64 lm[3],gm[3];
943: PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
944: PetscMPIInt d1,d2,rank;
946: PetscObjectGetComm((PetscObject)dm,&comm);
947: MPI_Comm_rank(comm,&rank);
948: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
949: MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);
950: #endif
951: if (ncomm != MPI_COMM_NULL) {
952: MPI_Comm_group(comm,&ggroup);
953: MPI_Comm_group(ncomm,&ngroup);
954: d1 = 0;
955: MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);
956: nid = d2;
957: MPI_Group_free(&ggroup);
958: MPI_Group_free(&ngroup);
959: MPI_Comm_free(&ncomm);
960: } else nid = 0.0;
962: /* Get connectivity */
963: DMPlexGetVTKCellHeight(dm,&cellHeight);
964: DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);
966: /* filter overlapped local cells */
967: DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);
968: ISGetIndices(gid,&idxs);
969: ISGetLocalSize(gid,&cum);
970: PetscMalloc1(cum,&idxs2);
971: for (c = cStart, cum = 0; c < cEnd; c++) {
972: if (idxs[c-cStart] < 0) continue;
973: idxs2[cum++] = idxs[c-cStart];
974: }
975: ISRestoreIndices(gid,&idxs);
976: if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
977: ISDestroy(&gid);
978: ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);
980: /* support for node-aware cell locality */
981: ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);
982: VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);
983: VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);
984: VecGetArray(cown,&array);
985: for (c = 0; c < numVertices; c++) array[c] = nid;
986: VecRestoreArray(cown,&array);
987: VecScatterCreate(cown,acis,acown,NULL,&sct);
988: VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
989: VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
990: ISDestroy(&acis);
991: VecScatterDestroy(&sct);
992: VecDestroy(&cown);
994: /* compute edgeCut */
995: for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
996: PetscMalloc1(cum,&work);
997: ISLocalToGlobalMappingCreateIS(gid,&g2l);
998: ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);
999: ISDestroy(&gid);
1000: VecGetArray(acown,&array);
1001: for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1002: PetscInt totl;
1004: totl = start[c+1]-start[c];
1005: ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);
1006: for (i = 0; i < totl; i++) {
1007: if (work[i] < 0) {
1008: ect += 1;
1009: ectn += (array[i + start[c]] != nid) ? 0 : 1;
1010: }
1011: }
1012: }
1013: PetscFree(work);
1014: VecRestoreArray(acown,&array);
1015: lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT;
1016: lm[1] = -numVertices;
1017: MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);
1018: PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);
1019: lm[0] = ect; /* edgeCut */
1020: lm[1] = ectn; /* node-aware edgeCut */
1021: lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1022: MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);
1023: PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);
1024: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1025: PetscViewerASCIIPrintf(viewer," Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.);
1026: #else
1027: PetscViewerASCIIPrintf(viewer," Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);
1028: #endif
1029: ISLocalToGlobalMappingDestroy(&g2l);
1030: PetscFree(start);
1031: PetscFree(adjacency);
1032: VecDestroy(&acown);
1033: } else {
1034: MPI_Comm comm;
1035: PetscInt *sizes, *hybsizes;
1036: PetscInt locDepth, depth, cellHeight, dim, d, pMax[4];
1037: PetscInt pStart, pEnd, p;
1038: PetscInt numLabels, l;
1039: const char *name;
1040: PetscMPIInt size;
1042: PetscObjectGetComm((PetscObject)dm,&comm);
1043: MPI_Comm_size(comm, &size);
1044: DMGetDimension(dm, &dim);
1045: DMPlexGetVTKCellHeight(dm, &cellHeight);
1046: PetscObjectGetName((PetscObject) dm, &name);
1047: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
1048: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
1049: if (cellHeight) {PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);}
1050: DMPlexGetDepth(dm, &locDepth);
1051: MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
1052: DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);
1053: PetscCalloc2(size,&sizes,size,&hybsizes);
1054: if (depth == 1) {
1055: DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
1056: pEnd = pEnd - pStart;
1057: pMax[0] -= pStart;
1058: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1059: MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1060: PetscViewerASCIIPrintf(viewer, " %d-cells:", 0);
1061: for (p = 0; p < size; ++p) {
1062: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1063: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1064: }
1065: PetscViewerASCIIPrintf(viewer, "\n");
1066: DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
1067: pEnd = pEnd - pStart;
1068: pMax[depth] -= pStart;
1069: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1070: MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1071: PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);
1072: for (p = 0; p < size; ++p) {
1073: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1074: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1075: }
1076: PetscViewerASCIIPrintf(viewer, "\n");
1077: } else {
1078: PetscMPIInt rank;
1079: MPI_Comm_rank(comm, &rank);
1080: for (d = 0; d <= dim; d++) {
1081: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
1082: pEnd -= pStart;
1083: pMax[d] -= pStart;
1084: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1085: MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1086: PetscViewerASCIIPrintf(viewer, " %D-cells:", d);
1087: for (p = 0; p < size; ++p) {
1088: if (!rank) {
1089: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1090: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1091: }
1092: }
1093: PetscViewerASCIIPrintf(viewer, "\n");
1094: }
1095: }
1096: PetscFree2(sizes,hybsizes);
1097: DMGetNumLabels(dm, &numLabels);
1098: if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
1099: for (l = 0; l < numLabels; ++l) {
1100: DMLabel label;
1101: const char *name;
1102: IS valueIS;
1103: const PetscInt *values;
1104: PetscInt numValues, v;
1106: DMGetLabelName(dm, l, &name);
1107: DMGetLabel(dm, name, &label);
1108: DMLabelGetNumValues(label, &numValues);
1109: PetscViewerASCIIPrintf(viewer, " %s: %D strata with value/size (", name, numValues);
1110: DMLabelGetValueIS(label, &valueIS);
1111: ISGetIndices(valueIS, &values);
1112: PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
1113: for (v = 0; v < numValues; ++v) {
1114: PetscInt size;
1116: DMLabelGetStratumSize(label, values[v], &size);
1117: if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
1118: PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
1119: }
1120: PetscViewerASCIIPrintf(viewer, ")\n");
1121: PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
1122: ISRestoreIndices(valueIS, &values);
1123: ISDestroy(&valueIS);
1124: }
1125: /* If no fields are specified, people do not want to see adjacency */
1126: if (dm->Nf) {
1127: PetscInt f;
1129: for (f = 0; f < dm->Nf; ++f) {
1130: const char *name;
1132: PetscObjectGetName(dm->fields[f].disc, &name);
1133: if (numLabels) {PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);}
1134: PetscViewerASCIIPushTab(viewer);
1135: if (dm->fields[f].label) {DMLabelView(dm->fields[f].label, viewer);}
1136: if (dm->fields[f].adjacency[0]) {
1137: if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");}
1138: else {PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");}
1139: } else {
1140: if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");}
1141: else {PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");}
1142: }
1143: PetscViewerASCIIPopTab(viewer);
1144: }
1145: }
1146: DMGetCoarseDM(dm, &cdm);
1147: if (cdm) {
1148: PetscViewerASCIIPushTab(viewer);
1149: DMPlexView_Ascii(cdm, viewer);
1150: PetscViewerASCIIPopTab(viewer);
1151: }
1152: }
1153: return(0);
1154: }
1156: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1157: {
1158: PetscDraw draw;
1159: DM cdm;
1160: PetscSection coordSection;
1161: Vec coordinates;
1162: const PetscScalar *coords;
1163: PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1164: PetscBool isnull;
1165: PetscInt dim, vStart, vEnd, cStart, cEnd, c, N;
1166: PetscMPIInt rank;
1167: PetscErrorCode ierr;
1170: DMGetCoordinateDim(dm, &dim);
1171: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1172: DMGetCoordinateDM(dm, &cdm);
1173: DMGetLocalSection(cdm, &coordSection);
1174: DMGetCoordinatesLocal(dm, &coordinates);
1175: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1176: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1178: PetscViewerDrawGetDraw(viewer, 0, &draw);
1179: PetscDrawIsNull(draw, &isnull);
1180: if (isnull) return(0);
1181: PetscDrawSetTitle(draw, "Mesh");
1183: VecGetLocalSize(coordinates, &N);
1184: VecGetArrayRead(coordinates, &coords);
1185: for (c = 0; c < N; c += dim) {
1186: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1187: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1188: }
1189: VecRestoreArrayRead(coordinates, &coords);
1190: MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1191: MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1192: PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1193: PetscDrawClear(draw);
1195: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1196: for (c = cStart; c < cEnd; ++c) {
1197: PetscScalar *coords = NULL;
1198: PetscInt numCoords,coneSize;
1200: DMPlexGetConeSize(dm, c, &coneSize);
1201: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1202: switch (coneSize) {
1203: case 3:
1204: PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1205: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1206: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1207: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1208: break;
1209: case 4:
1210: PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1211: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1212: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1213: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1214: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1215: break;
1216: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1217: }
1218: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1219: }
1220: for (c = cStart; c < cEnd; ++c) {
1221: PetscScalar *coords = NULL;
1222: PetscInt numCoords,coneSize;
1224: DMPlexGetConeSize(dm, c, &coneSize);
1225: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1226: switch (coneSize) {
1227: case 3:
1228: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1229: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1230: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1231: break;
1232: case 4:
1233: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1234: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1235: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
1236: PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1237: break;
1238: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1239: }
1240: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1241: }
1242: PetscDrawFlush(draw);
1243: PetscDrawPause(draw);
1244: PetscDrawSave(draw);
1245: return(0);
1246: }
1248: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1249: {
1250: PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1251: char name[PETSC_MAX_PATH_LEN];
1257: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
1258: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
1259: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
1260: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
1261: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
1262: if (iascii) {
1263: PetscViewerFormat format;
1264: PetscViewerGetFormat(viewer, &format);
1265: if (format == PETSC_VIEWER_ASCII_GLVIS) {
1266: DMPlexView_GLVis(dm, viewer);
1267: } else {
1268: DMPlexView_Ascii(dm, viewer);
1269: }
1270: } else if (ishdf5) {
1271: #if defined(PETSC_HAVE_HDF5)
1272: DMPlexView_HDF5_Internal(dm, viewer);
1273: #else
1274: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1275: #endif
1276: } else if (isvtk) {
1277: DMPlexVTKWriteAll((PetscObject) dm,viewer);
1278: } else if (isdraw) {
1279: DMPlexView_Draw(dm, viewer);
1280: } else if (isglvis) {
1281: DMPlexView_GLVis(dm, viewer);
1282: } else {
1283: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1284: }
1285: /* Optionally view the partition */
1286: PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1287: if (flg) {
1288: Vec ranks;
1289: DMPlexCreateRankField(dm, &ranks);
1290: VecView(ranks, viewer);
1291: VecDestroy(&ranks);
1292: }
1293: /* Optionally view a label */
1294: PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, PETSC_MAX_PATH_LEN, &flg);
1295: if (flg) {
1296: DMLabel label;
1297: Vec val;
1299: DMGetLabel(dm, name, &label);
1300: if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1301: DMPlexCreateLabelField(dm, label, &val);
1302: VecView(val, viewer);
1303: VecDestroy(&val);
1304: }
1305: return(0);
1306: }
1308: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1309: {
1310: PetscBool ishdf5;
1316: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
1317: if (ishdf5) {
1318: #if defined(PETSC_HAVE_HDF5)
1319: PetscViewerFormat format;
1320: PetscViewerGetFormat(viewer, &format);
1321: if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1322: DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1323: } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1324: DMPlexLoad_HDF5_Internal(dm, viewer);
1325: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1326: #else
1327: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1328: #endif
1329: } else {
1330: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1331: }
1332: return(0);
1333: }
1335: PetscErrorCode DMDestroy_Plex(DM dm)
1336: {
1337: DM_Plex *mesh = (DM_Plex*) dm->data;
1341: PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1342: PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1343: PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);
1344: if (--mesh->refct > 0) return(0);
1345: PetscSectionDestroy(&mesh->coneSection);
1346: PetscFree(mesh->cones);
1347: PetscFree(mesh->coneOrientations);
1348: PetscSectionDestroy(&mesh->supportSection);
1349: PetscSectionDestroy(&mesh->subdomainSection);
1350: PetscFree(mesh->supports);
1351: PetscFree(mesh->facesTmp);
1352: PetscFree(mesh->tetgenOpts);
1353: PetscFree(mesh->triangleOpts);
1354: PetscPartitionerDestroy(&mesh->partitioner);
1355: DMLabelDestroy(&mesh->subpointMap);
1356: ISDestroy(&mesh->globalVertexNumbers);
1357: ISDestroy(&mesh->globalCellNumbers);
1358: PetscSectionDestroy(&mesh->anchorSection);
1359: ISDestroy(&mesh->anchorIS);
1360: PetscSectionDestroy(&mesh->parentSection);
1361: PetscFree(mesh->parents);
1362: PetscFree(mesh->childIDs);
1363: PetscSectionDestroy(&mesh->childSection);
1364: PetscFree(mesh->children);
1365: DMDestroy(&mesh->referenceTree);
1366: PetscGridHashDestroy(&mesh->lbox);
1367: /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1368: PetscFree(mesh);
1369: return(0);
1370: }
1372: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1373: {
1374: PetscSection sectionGlobal;
1375: PetscInt bs = -1, mbs;
1376: PetscInt localSize;
1377: PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1378: PetscErrorCode ierr;
1379: MatType mtype;
1380: ISLocalToGlobalMapping ltog;
1383: MatInitializePackage();
1384: mtype = dm->mattype;
1385: DMGetGlobalSection(dm, §ionGlobal);
1386: /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1387: PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1388: MatCreate(PetscObjectComm((PetscObject)dm), J);
1389: MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1390: MatSetType(*J, mtype);
1391: MatSetFromOptions(*J);
1392: MatGetBlockSize(*J, &mbs);
1393: if (mbs > 1) bs = mbs;
1394: PetscStrcmp(mtype, MATSHELL, &isShell);
1395: PetscStrcmp(mtype, MATBAIJ, &isBlock);
1396: PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1397: PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1398: PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1399: PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1400: PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1401: PetscStrcmp(mtype, MATIS, &isMatIS);
1402: if (!isShell) {
1403: PetscSection subSection;
1404: PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1405: PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1406: PetscInt pStart, pEnd, p, dof, cdof;
1408: /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
1409: if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
1410: PetscSection section;
1411: PetscInt size;
1413: DMGetLocalSection(dm, §ion);
1414: PetscSectionGetStorageSize(section, &size);
1415: PetscMalloc1(size,<ogidx);
1416: DMPlexGetSubdomainSection(dm, &subSection);
1417: } else {
1418: DMGetLocalToGlobalMapping(dm,<og);
1419: }
1420: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1421: for (p = pStart, lsize = 0; p < pEnd; ++p) {
1422: PetscInt bdof;
1424: PetscSectionGetDof(sectionGlobal, p, &dof);
1425: PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1426: dof = dof < 0 ? -(dof+1) : dof;
1427: bdof = cdof && (dof-cdof) ? 1 : dof;
1428: if (dof) {
1429: if (bs < 0) {bs = bdof;}
1430: else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1431: }
1432: if (isMatIS) {
1433: PetscInt loff,c,off;
1434: PetscSectionGetOffset(subSection, p, &loff);
1435: PetscSectionGetOffset(sectionGlobal, p, &off);
1436: for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1437: }
1438: }
1439: /* Must have same blocksize on all procs (some might have no points) */
1440: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1441: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1442: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1443: else {bs = bsMinMax[0];}
1444: bs = PetscMax(1,bs);
1445: if (isMatIS) { /* Must reduce indices by blocksize */
1446: PetscInt l;
1448: lsize = lsize/bs;
1449: if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs;
1450: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, <og);
1451: }
1452: MatSetLocalToGlobalMapping(*J,ltog,ltog);
1453: if (isMatIS) {
1454: ISLocalToGlobalMappingDestroy(<og);
1455: }
1456: PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1457: DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1458: PetscFree4(dnz, onz, dnzu, onzu);
1459: }
1460: MatSetDM(*J, dm);
1461: return(0);
1462: }
1464: /*@
1465: DMPlexGetSubdomainSection - Returns the section associated with the subdomain
1467: Not collective
1469: Input Parameter:
1470: . mesh - The DMPlex
1472: Output Parameters:
1473: . subsection - The subdomain section
1475: Level: developer
1477: .seealso:
1478: @*/
1479: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1480: {
1481: DM_Plex *mesh = (DM_Plex*) dm->data;
1486: if (!mesh->subdomainSection) {
1487: PetscSection section;
1488: PetscSF sf;
1490: PetscSFCreate(PETSC_COMM_SELF,&sf);
1491: DMGetLocalSection(dm,§ion);
1492: PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1493: PetscSFDestroy(&sf);
1494: }
1495: *subsection = mesh->subdomainSection;
1496: return(0);
1497: }
1499: /*@
1500: DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1502: Not collective
1504: Input Parameter:
1505: . mesh - The DMPlex
1507: Output Parameters:
1508: + pStart - The first mesh point
1509: - pEnd - The upper bound for mesh points
1511: Level: beginner
1513: .seealso: DMPlexCreate(), DMPlexSetChart()
1514: @*/
1515: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1516: {
1517: DM_Plex *mesh = (DM_Plex*) dm->data;
1522: PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1523: return(0);
1524: }
1526: /*@
1527: DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1529: Not collective
1531: Input Parameters:
1532: + mesh - The DMPlex
1533: . pStart - The first mesh point
1534: - pEnd - The upper bound for mesh points
1536: Output Parameters:
1538: Level: beginner
1540: .seealso: DMPlexCreate(), DMPlexGetChart()
1541: @*/
1542: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1543: {
1544: DM_Plex *mesh = (DM_Plex*) dm->data;
1549: PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1550: PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1551: return(0);
1552: }
1554: /*@
1555: DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
1557: Not collective
1559: Input Parameters:
1560: + mesh - The DMPlex
1561: - p - The point, which must lie in the chart set with DMPlexSetChart()
1563: Output Parameter:
1564: . size - The cone size for point p
1566: Level: beginner
1568: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1569: @*/
1570: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1571: {
1572: DM_Plex *mesh = (DM_Plex*) dm->data;
1578: PetscSectionGetDof(mesh->coneSection, p, size);
1579: return(0);
1580: }
1582: /*@
1583: DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
1585: Not collective
1587: Input Parameters:
1588: + mesh - The DMPlex
1589: . p - The point, which must lie in the chart set with DMPlexSetChart()
1590: - size - The cone size for point p
1592: Output Parameter:
1594: Note:
1595: This should be called after DMPlexSetChart().
1597: Level: beginner
1599: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1600: @*/
1601: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1602: {
1603: DM_Plex *mesh = (DM_Plex*) dm->data;
1608: PetscSectionSetDof(mesh->coneSection, p, size);
1610: mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1611: return(0);
1612: }
1614: /*@
1615: DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
1617: Not collective
1619: Input Parameters:
1620: + mesh - The DMPlex
1621: . p - The point, which must lie in the chart set with DMPlexSetChart()
1622: - size - The additional cone size for point p
1624: Output Parameter:
1626: Note:
1627: This should be called after DMPlexSetChart().
1629: Level: beginner
1631: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1632: @*/
1633: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1634: {
1635: DM_Plex *mesh = (DM_Plex*) dm->data;
1636: PetscInt csize;
1641: PetscSectionAddDof(mesh->coneSection, p, size);
1642: PetscSectionGetDof(mesh->coneSection, p, &csize);
1644: mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1645: return(0);
1646: }
1648: /*@C
1649: DMPlexGetCone - Return the points on the in-edges for this point in the DAG
1651: Not collective
1653: Input Parameters:
1654: + dm - The DMPlex
1655: - p - The point, which must lie in the chart set with DMPlexSetChart()
1657: Output Parameter:
1658: . cone - An array of points which are on the in-edges for point p
1660: Level: beginner
1662: Fortran Notes:
1663: Since it returns an array, this routine is only available in Fortran 90, and you must
1664: include petsc.h90 in your code.
1665: You must also call DMPlexRestoreCone() after you finish using the returned array.
1666: DMPlexRestoreCone() is not needed/available in C.
1668: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1669: @*/
1670: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1671: {
1672: DM_Plex *mesh = (DM_Plex*) dm->data;
1673: PetscInt off;
1679: PetscSectionGetOffset(mesh->coneSection, p, &off);
1680: *cone = &mesh->cones[off];
1681: return(0);
1682: }
1684: /*@C
1685: DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
1687: Not collective
1689: Input Parameters:
1690: + dm - The DMPlex
1691: - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
1693: Output Parameter:
1694: + pConesSection - PetscSection describing the layout of pCones
1695: - pCones - An array of points which are on the in-edges for the point set p
1697: Level: intermediate
1699: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1700: @*/
1701: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1702: {
1703: PetscSection cs, newcs;
1704: PetscInt *cones;
1705: PetscInt *newarr=NULL;
1706: PetscInt n;
1707: PetscErrorCode ierr;
1710: DMPlexGetCones(dm, &cones);
1711: DMPlexGetConeSection(dm, &cs);
1712: PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1713: if (pConesSection) *pConesSection = newcs;
1714: if (pCones) {
1715: PetscSectionGetStorageSize(newcs, &n);
1716: ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1717: }
1718: return(0);
1719: }
1721: /*@
1722: DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
1724: Not collective
1726: Input Parameters:
1727: + dm - The DMPlex
1728: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
1730: Output Parameter:
1731: . expandedPoints - An array of vertices recursively expanded from input points
1733: Level: advanced
1735: Notes:
1736: Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
1737: There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.
1739: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth()
1740: @*/
1741: PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
1742: {
1743: IS *expandedPointsAll;
1744: PetscInt depth;
1745: PetscErrorCode ierr;
1751: DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);
1752: *expandedPoints = expandedPointsAll[0];
1753: PetscObjectReference((PetscObject)expandedPointsAll[0]);
1754: DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);
1755: return(0);
1756: }
1758: /*@
1759: DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones).
1761: Not collective
1763: Input Parameters:
1764: + dm - The DMPlex
1765: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
1767: Output Parameter:
1768: + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
1769: . expandedPoints - (optional) An array of index sets with recursively expanded cones
1770: - sections - (optional) An array of sections which describe mappings from points to their cone points
1772: Level: advanced
1774: Notes:
1775: Like DMPlexGetConeTuple() but recursive.
1777: Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points.
1778: For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
1780: Array section has size equal to depth. Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows:
1781: (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
1782: (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].
1784: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
1785: @*/
1786: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
1787: {
1788: const PetscInt *arr0=NULL, *cone=NULL;
1789: PetscInt *arr=NULL, *newarr=NULL;
1790: PetscInt d, depth_, i, n, newn, cn, co, start, end;
1791: IS *expandedPoints_;
1792: PetscSection *sections_;
1793: PetscErrorCode ierr;
1801: ISGetLocalSize(points, &n);
1802: ISGetIndices(points, &arr0);
1803: DMPlexGetDepth(dm, &depth_);
1804: PetscCalloc1(depth_, &expandedPoints_);
1805: PetscCalloc1(depth_, §ions_);
1806: arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
1807: for (d=depth_-1; d>=0; d--) {
1808: PetscSectionCreate(PETSC_COMM_SELF, §ions_[d]);
1809: PetscSectionSetChart(sections_[d], 0, n);
1810: for (i=0; i<n; i++) {
1811: DMPlexGetDepthStratum(dm, d+1, &start, &end);
1812: if (arr[i] >= start && arr[i] < end) {
1813: DMPlexGetConeSize(dm, arr[i], &cn);
1814: PetscSectionSetDof(sections_[d], i, cn);
1815: } else {
1816: PetscSectionSetDof(sections_[d], i, 1);
1817: }
1818: }
1819: PetscSectionSetUp(sections_[d]);
1820: PetscSectionGetStorageSize(sections_[d], &newn);
1821: PetscMalloc1(newn, &newarr);
1822: for (i=0; i<n; i++) {
1823: PetscSectionGetDof(sections_[d], i, &cn);
1824: PetscSectionGetOffset(sections_[d], i, &co);
1825: if (cn > 1) {
1826: DMPlexGetCone(dm, arr[i], &cone);
1827: PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));
1828: } else {
1829: newarr[co] = arr[i];
1830: }
1831: }
1832: ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);
1833: arr = newarr;
1834: n = newn;
1835: }
1836: *depth = depth_;
1837: if (expandedPoints) *expandedPoints = expandedPoints_;
1838: else {
1839: for (d=0; d<depth_; d++) {ISDestroy(&expandedPoints_[d]);}
1840: PetscFree(expandedPoints_);
1841: }
1842: if (sections) *sections = sections_;
1843: else {
1844: for (d=0; d<depth_; d++) {PetscSectionDestroy(§ions_[d]);}
1845: PetscFree(sections_);
1846: }
1847: return(0);
1848: }
1850: /*@
1851: DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive
1853: Not collective
1855: Input Parameters:
1856: + dm - The DMPlex
1857: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
1859: Output Parameter:
1860: + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
1861: . expandedPoints - (optional) An array of recursively expanded cones
1862: - sections - (optional) An array of sections which describe mappings from points to their cone points
1864: Level: advanced
1866: Notes:
1867: See DMPlexGetConeRecursive() for details.
1869: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
1870: @*/
1871: PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
1872: {
1873: PetscInt d, depth_;
1874: PetscErrorCode ierr;
1877: DMPlexGetDepth(dm, &depth_);
1878: if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
1879: if (depth) *depth = 0;
1880: if (expandedPoints) {
1881: for (d=0; d<depth_; d++) {ISDestroy(&((*expandedPoints)[d]));}
1882: PetscFree(*expandedPoints);
1883: }
1884: if (sections) {
1885: for (d=0; d<depth_; d++) {PetscSectionDestroy(&((*sections)[d]));}
1886: PetscFree(*sections);
1887: }
1888: return(0);
1889: }
1891: /*@
1892: DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point
1894: Not collective
1896: Input Parameters:
1897: + mesh - The DMPlex
1898: . p - The point, which must lie in the chart set with DMPlexSetChart()
1899: - cone - An array of points which are on the in-edges for point p
1901: Output Parameter:
1903: Note:
1904: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1906: Developer Note: Why not call this DMPlexSetCover()
1908: Level: beginner
1910: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1911: @*/
1912: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1913: {
1914: DM_Plex *mesh = (DM_Plex*) dm->data;
1915: PetscInt pStart, pEnd;
1916: PetscInt dof, off, c;
1921: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1922: PetscSectionGetDof(mesh->coneSection, p, &dof);
1924: PetscSectionGetOffset(mesh->coneSection, p, &off);
1925: 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);
1926: for (c = 0; c < dof; ++c) {
1927: 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);
1928: mesh->cones[off+c] = cone[c];
1929: }
1930: return(0);
1931: }
1933: /*@C
1934: DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
1936: Not collective
1938: Input Parameters:
1939: + mesh - The DMPlex
1940: - p - The point, which must lie in the chart set with DMPlexSetChart()
1942: Output Parameter:
1943: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1944: integer giving the prescription for cone traversal. If it is negative, the cone is
1945: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1946: the index of the cone point on which to start.
1948: Level: beginner
1950: Fortran Notes:
1951: Since it returns an array, this routine is only available in Fortran 90, and you must
1952: include petsc.h90 in your code.
1953: You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1954: DMPlexRestoreConeOrientation() is not needed/available in C.
1956: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1957: @*/
1958: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1959: {
1960: DM_Plex *mesh = (DM_Plex*) dm->data;
1961: PetscInt off;
1966: #if defined(PETSC_USE_DEBUG)
1967: {
1968: PetscInt dof;
1969: PetscSectionGetDof(mesh->coneSection, p, &dof);
1971: }
1972: #endif
1973: PetscSectionGetOffset(mesh->coneSection, p, &off);
1975: *coneOrientation = &mesh->coneOrientations[off];
1976: return(0);
1977: }
1979: /*@
1980: DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
1982: Not collective
1984: Input Parameters:
1985: + mesh - The DMPlex
1986: . p - The point, which must lie in the chart set with DMPlexSetChart()
1987: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1988: integer giving the prescription for cone traversal. If it is negative, the cone is
1989: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1990: the index of the cone point on which to start.
1992: Output Parameter:
1994: Note:
1995: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1997: Level: beginner
1999: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2000: @*/
2001: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
2002: {
2003: DM_Plex *mesh = (DM_Plex*) dm->data;
2004: PetscInt pStart, pEnd;
2005: PetscInt dof, off, c;
2010: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2011: PetscSectionGetDof(mesh->coneSection, p, &dof);
2013: PetscSectionGetOffset(mesh->coneSection, p, &off);
2014: 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);
2015: for (c = 0; c < dof; ++c) {
2016: PetscInt cdof, o = coneOrientation[c];
2018: PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
2019: 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);
2020: mesh->coneOrientations[off+c] = o;
2021: }
2022: return(0);
2023: }
2025: /*@
2026: DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
2028: Not collective
2030: Input Parameters:
2031: + mesh - The DMPlex
2032: . p - The point, which must lie in the chart set with DMPlexSetChart()
2033: . conePos - The local index in the cone where the point should be put
2034: - conePoint - The mesh point to insert
2036: Level: beginner
2038: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2039: @*/
2040: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
2041: {
2042: DM_Plex *mesh = (DM_Plex*) dm->data;
2043: PetscInt pStart, pEnd;
2044: PetscInt dof, off;
2049: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2050: 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);
2051: 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);
2052: PetscSectionGetDof(mesh->coneSection, p, &dof);
2053: PetscSectionGetOffset(mesh->coneSection, p, &off);
2054: 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);
2055: mesh->cones[off+conePos] = conePoint;
2056: return(0);
2057: }
2059: /*@
2060: DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
2062: Not collective
2064: Input Parameters:
2065: + mesh - The DMPlex
2066: . p - The point, which must lie in the chart set with DMPlexSetChart()
2067: . conePos - The local index in the cone where the point should be put
2068: - coneOrientation - The point orientation to insert
2070: Level: beginner
2072: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2073: @*/
2074: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
2075: {
2076: DM_Plex *mesh = (DM_Plex*) dm->data;
2077: PetscInt pStart, pEnd;
2078: PetscInt dof, off;
2083: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2084: 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);
2085: PetscSectionGetDof(mesh->coneSection, p, &dof);
2086: PetscSectionGetOffset(mesh->coneSection, p, &off);
2087: 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);
2088: mesh->coneOrientations[off+conePos] = coneOrientation;
2089: return(0);
2090: }
2092: /*@
2093: DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
2095: Not collective
2097: Input Parameters:
2098: + mesh - The DMPlex
2099: - p - The point, which must lie in the chart set with DMPlexSetChart()
2101: Output Parameter:
2102: . size - The support size for point p
2104: Level: beginner
2106: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
2107: @*/
2108: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
2109: {
2110: DM_Plex *mesh = (DM_Plex*) dm->data;
2116: PetscSectionGetDof(mesh->supportSection, p, size);
2117: return(0);
2118: }
2120: /*@
2121: DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
2123: Not collective
2125: Input Parameters:
2126: + mesh - The DMPlex
2127: . p - The point, which must lie in the chart set with DMPlexSetChart()
2128: - size - The support size for point p
2130: Output Parameter:
2132: Note:
2133: This should be called after DMPlexSetChart().
2135: Level: beginner
2137: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
2138: @*/
2139: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
2140: {
2141: DM_Plex *mesh = (DM_Plex*) dm->data;
2146: PetscSectionSetDof(mesh->supportSection, p, size);
2148: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
2149: return(0);
2150: }
2152: /*@C
2153: DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
2155: Not collective
2157: Input Parameters:
2158: + mesh - The DMPlex
2159: - p - The point, which must lie in the chart set with DMPlexSetChart()
2161: Output Parameter:
2162: . support - An array of points which are on the out-edges for point p
2164: Level: beginner
2166: Fortran Notes:
2167: Since it returns an array, this routine is only available in Fortran 90, and you must
2168: include petsc.h90 in your code.
2169: You must also call DMPlexRestoreSupport() after you finish using the returned array.
2170: DMPlexRestoreSupport() is not needed/available in C.
2172: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2173: @*/
2174: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
2175: {
2176: DM_Plex *mesh = (DM_Plex*) dm->data;
2177: PetscInt off;
2183: PetscSectionGetOffset(mesh->supportSection, p, &off);
2184: *support = &mesh->supports[off];
2185: return(0);
2186: }
2188: /*@
2189: DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
2191: Not collective
2193: Input Parameters:
2194: + mesh - The DMPlex
2195: . p - The point, which must lie in the chart set with DMPlexSetChart()
2196: - support - An array of points which are on the out-edges for point p
2198: Output Parameter:
2200: Note:
2201: This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
2203: Level: beginner
2205: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
2206: @*/
2207: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
2208: {
2209: DM_Plex *mesh = (DM_Plex*) dm->data;
2210: PetscInt pStart, pEnd;
2211: PetscInt dof, off, c;
2216: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2217: PetscSectionGetDof(mesh->supportSection, p, &dof);
2219: PetscSectionGetOffset(mesh->supportSection, p, &off);
2220: 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);
2221: for (c = 0; c < dof; ++c) {
2222: 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);
2223: mesh->supports[off+c] = support[c];
2224: }
2225: return(0);
2226: }
2228: /*@
2229: DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
2231: Not collective
2233: Input Parameters:
2234: + mesh - The DMPlex
2235: . p - The point, which must lie in the chart set with DMPlexSetChart()
2236: . supportPos - The local index in the cone where the point should be put
2237: - supportPoint - The mesh point to insert
2239: Level: beginner
2241: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2242: @*/
2243: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
2244: {
2245: DM_Plex *mesh = (DM_Plex*) dm->data;
2246: PetscInt pStart, pEnd;
2247: PetscInt dof, off;
2252: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2253: PetscSectionGetDof(mesh->supportSection, p, &dof);
2254: PetscSectionGetOffset(mesh->supportSection, p, &off);
2255: 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);
2256: 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);
2257: 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);
2258: mesh->supports[off+supportPos] = supportPoint;
2259: return(0);
2260: }
2262: /*@C
2263: DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
2265: Not collective
2267: Input Parameters:
2268: + mesh - The DMPlex
2269: . p - The point, which must lie in the chart set with DMPlexSetChart()
2270: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2271: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2273: Output Parameters:
2274: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2275: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2277: Note:
2278: If using internal storage (points is NULL on input), each call overwrites the last output.
2280: Fortran Notes:
2281: Since it returns an array, this routine is only available in Fortran 90, and you must
2282: include petsc.h90 in your code.
2284: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2286: Level: beginner
2288: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2289: @*/
2290: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2291: {
2292: DM_Plex *mesh = (DM_Plex*) dm->data;
2293: PetscInt *closure, *fifo;
2294: const PetscInt *tmp = NULL, *tmpO = NULL;
2295: PetscInt tmpSize, t;
2296: PetscInt depth = 0, maxSize;
2297: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
2298: PetscErrorCode ierr;
2302: DMPlexGetDepth(dm, &depth);
2303: /* This is only 1-level */
2304: if (useCone) {
2305: DMPlexGetConeSize(dm, p, &tmpSize);
2306: DMPlexGetCone(dm, p, &tmp);
2307: DMPlexGetConeOrientation(dm, p, &tmpO);
2308: } else {
2309: DMPlexGetSupportSize(dm, p, &tmpSize);
2310: DMPlexGetSupport(dm, p, &tmp);
2311: }
2312: if (depth == 1) {
2313: if (*points) {
2314: closure = *points;
2315: } else {
2316: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2317: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2318: }
2319: closure[0] = p; closure[1] = 0;
2320: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2321: closure[closureSize] = tmp[t];
2322: closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2323: }
2324: if (numPoints) *numPoints = closureSize/2;
2325: if (points) *points = closure;
2326: return(0);
2327: }
2328: {
2329: PetscInt c, coneSeries, s,supportSeries;
2331: c = mesh->maxConeSize;
2332: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2333: s = mesh->maxSupportSize;
2334: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2335: maxSize = 2*PetscMax(coneSeries,supportSeries);
2336: }
2337: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2338: if (*points) {
2339: closure = *points;
2340: } else {
2341: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2342: }
2343: closure[0] = p; closure[1] = 0;
2344: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2345: const PetscInt cp = tmp[t];
2346: const PetscInt co = tmpO ? tmpO[t] : 0;
2348: closure[closureSize] = cp;
2349: closure[closureSize+1] = co;
2350: fifo[fifoSize] = cp;
2351: fifo[fifoSize+1] = co;
2352: }
2353: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2354: while (fifoSize - fifoStart) {
2355: const PetscInt q = fifo[fifoStart];
2356: const PetscInt o = fifo[fifoStart+1];
2357: const PetscInt rev = o >= 0 ? 0 : 1;
2358: const PetscInt off = rev ? -(o+1) : o;
2360: if (useCone) {
2361: DMPlexGetConeSize(dm, q, &tmpSize);
2362: DMPlexGetCone(dm, q, &tmp);
2363: DMPlexGetConeOrientation(dm, q, &tmpO);
2364: } else {
2365: DMPlexGetSupportSize(dm, q, &tmpSize);
2366: DMPlexGetSupport(dm, q, &tmp);
2367: tmpO = NULL;
2368: }
2369: for (t = 0; t < tmpSize; ++t) {
2370: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
2371: const PetscInt cp = tmp[i];
2372: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2373: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2374: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2375: PetscInt co = tmpO ? tmpO[i] : 0;
2376: PetscInt c;
2378: if (rev) {
2379: PetscInt childSize, coff;
2380: DMPlexGetConeSize(dm, cp, &childSize);
2381: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2382: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2383: }
2384: /* Check for duplicate */
2385: for (c = 0; c < closureSize; c += 2) {
2386: if (closure[c] == cp) break;
2387: }
2388: if (c == closureSize) {
2389: closure[closureSize] = cp;
2390: closure[closureSize+1] = co;
2391: fifo[fifoSize] = cp;
2392: fifo[fifoSize+1] = co;
2393: closureSize += 2;
2394: fifoSize += 2;
2395: }
2396: }
2397: fifoStart += 2;
2398: }
2399: if (numPoints) *numPoints = closureSize/2;
2400: if (points) *points = closure;
2401: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2402: return(0);
2403: }
2405: /*@C
2406: DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG with a specified initial orientation
2408: Not collective
2410: Input Parameters:
2411: + mesh - The DMPlex
2412: . p - The point, which must lie in the chart set with DMPlexSetChart()
2413: . orientation - The orientation of the point
2414: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2415: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2417: Output Parameters:
2418: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2419: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2421: Note:
2422: If using internal storage (points is NULL on input), each call overwrites the last output.
2424: Fortran Notes:
2425: Since it returns an array, this routine is only available in Fortran 90, and you must
2426: include petsc.h90 in your code.
2428: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2430: Level: beginner
2432: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2433: @*/
2434: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2435: {
2436: DM_Plex *mesh = (DM_Plex*) dm->data;
2437: PetscInt *closure, *fifo;
2438: const PetscInt *tmp = NULL, *tmpO = NULL;
2439: PetscInt tmpSize, t;
2440: PetscInt depth = 0, maxSize;
2441: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
2442: PetscErrorCode ierr;
2446: DMPlexGetDepth(dm, &depth);
2447: /* This is only 1-level */
2448: if (useCone) {
2449: DMPlexGetConeSize(dm, p, &tmpSize);
2450: DMPlexGetCone(dm, p, &tmp);
2451: DMPlexGetConeOrientation(dm, p, &tmpO);
2452: } else {
2453: DMPlexGetSupportSize(dm, p, &tmpSize);
2454: DMPlexGetSupport(dm, p, &tmp);
2455: }
2456: if (depth == 1) {
2457: if (*points) {
2458: closure = *points;
2459: } else {
2460: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2461: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2462: }
2463: closure[0] = p; closure[1] = ornt;
2464: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2465: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2466: closure[closureSize] = tmp[i];
2467: closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2468: }
2469: if (numPoints) *numPoints = closureSize/2;
2470: if (points) *points = closure;
2471: return(0);
2472: }
2473: {
2474: PetscInt c, coneSeries, s,supportSeries;
2476: c = mesh->maxConeSize;
2477: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2478: s = mesh->maxSupportSize;
2479: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2480: maxSize = 2*PetscMax(coneSeries,supportSeries);
2481: }
2482: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2483: if (*points) {
2484: closure = *points;
2485: } else {
2486: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2487: }
2488: closure[0] = p; closure[1] = ornt;
2489: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2490: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2491: const PetscInt cp = tmp[i];
2492: PetscInt co = tmpO ? tmpO[i] : 0;
2494: if (ornt < 0) {
2495: PetscInt childSize, coff;
2496: DMPlexGetConeSize(dm, cp, &childSize);
2497: coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2498: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2499: }
2500: closure[closureSize] = cp;
2501: closure[closureSize+1] = co;
2502: fifo[fifoSize] = cp;
2503: fifo[fifoSize+1] = co;
2504: }
2505: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2506: while (fifoSize - fifoStart) {
2507: const PetscInt q = fifo[fifoStart];
2508: const PetscInt o = fifo[fifoStart+1];
2509: const PetscInt rev = o >= 0 ? 0 : 1;
2510: const PetscInt off = rev ? -(o+1) : o;
2512: if (useCone) {
2513: DMPlexGetConeSize(dm, q, &tmpSize);
2514: DMPlexGetCone(dm, q, &tmp);
2515: DMPlexGetConeOrientation(dm, q, &tmpO);
2516: } else {
2517: DMPlexGetSupportSize(dm, q, &tmpSize);
2518: DMPlexGetSupport(dm, q, &tmp);
2519: tmpO = NULL;
2520: }
2521: for (t = 0; t < tmpSize; ++t) {
2522: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
2523: const PetscInt cp = tmp[i];
2524: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2525: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2526: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2527: PetscInt co = tmpO ? tmpO[i] : 0;
2528: PetscInt c;
2530: if (rev) {
2531: PetscInt childSize, coff;
2532: DMPlexGetConeSize(dm, cp, &childSize);
2533: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2534: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2535: }
2536: /* Check for duplicate */
2537: for (c = 0; c < closureSize; c += 2) {
2538: if (closure[c] == cp) break;
2539: }
2540: if (c == closureSize) {
2541: closure[closureSize] = cp;
2542: closure[closureSize+1] = co;
2543: fifo[fifoSize] = cp;
2544: fifo[fifoSize+1] = co;
2545: closureSize += 2;
2546: fifoSize += 2;
2547: }
2548: }
2549: fifoStart += 2;
2550: }
2551: if (numPoints) *numPoints = closureSize/2;
2552: if (points) *points = closure;
2553: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2554: return(0);
2555: }
2557: /*@C
2558: DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
2560: Not collective
2562: Input Parameters:
2563: + mesh - The DMPlex
2564: . p - The point, which must lie in the chart set with DMPlexSetChart()
2565: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2566: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
2567: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
2569: Note:
2570: If not using internal storage (points is not NULL on input), this call is unnecessary
2572: Fortran Notes:
2573: Since it returns an array, this routine is only available in Fortran 90, and you must
2574: include petsc.h90 in your code.
2576: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2578: Level: beginner
2580: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2581: @*/
2582: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2583: {
2590: DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2591: if (numPoints) *numPoints = 0;
2592: return(0);
2593: }
2595: /*@
2596: DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
2598: Not collective
2600: Input Parameter:
2601: . mesh - The DMPlex
2603: Output Parameters:
2604: + maxConeSize - The maximum number of in-edges
2605: - maxSupportSize - The maximum number of out-edges
2607: Level: beginner
2609: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2610: @*/
2611: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2612: {
2613: DM_Plex *mesh = (DM_Plex*) dm->data;
2617: if (maxConeSize) *maxConeSize = mesh->maxConeSize;
2618: if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2619: return(0);
2620: }
2622: PetscErrorCode DMSetUp_Plex(DM dm)
2623: {
2624: DM_Plex *mesh = (DM_Plex*) dm->data;
2625: PetscInt size;
2630: PetscSectionSetUp(mesh->coneSection);
2631: PetscSectionGetStorageSize(mesh->coneSection, &size);
2632: PetscMalloc1(size, &mesh->cones);
2633: PetscCalloc1(size, &mesh->coneOrientations);
2634: if (mesh->maxSupportSize) {
2635: PetscSectionSetUp(mesh->supportSection);
2636: PetscSectionGetStorageSize(mesh->supportSection, &size);
2637: PetscMalloc1(size, &mesh->supports);
2638: }
2639: return(0);
2640: }
2642: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2643: {
2647: if (subdm) {DMClone(dm, subdm);}
2648: DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2649: if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2650: if (dm->useNatural && dm->sfMigration) {
2651: PetscSF sfMigrationInv,sfNatural;
2652: PetscSection section, sectionSeq;
2654: (*subdm)->sfMigration = dm->sfMigration;
2655: PetscObjectReference((PetscObject) dm->sfMigration);
2656: DMGetLocalSection((*subdm), §ion);
2657: PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2658: PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq);
2659: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2661: DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2662: (*subdm)->sfNatural = sfNatural;
2663: PetscSectionDestroy(§ionSeq);
2664: PetscSFDestroy(&sfMigrationInv);
2665: }
2666: return(0);
2667: }
2669: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2670: {
2672: PetscInt i = 0;
2675: DMClone(dms[0], superdm);
2676: DMCreateSectionSuperDM(dms, len, is, superdm);
2677: (*superdm)->useNatural = PETSC_FALSE;
2678: for (i = 0; i < len; i++){
2679: if (dms[i]->useNatural && dms[i]->sfMigration) {
2680: PetscSF sfMigrationInv,sfNatural;
2681: PetscSection section, sectionSeq;
2683: (*superdm)->sfMigration = dms[i]->sfMigration;
2684: PetscObjectReference((PetscObject) dms[i]->sfMigration);
2685: (*superdm)->useNatural = PETSC_TRUE;
2686: DMGetLocalSection((*superdm), §ion);
2687: PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2688: PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq);
2689: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2691: DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2692: (*superdm)->sfNatural = sfNatural;
2693: PetscSectionDestroy(§ionSeq);
2694: PetscSFDestroy(&sfMigrationInv);
2695: break;
2696: }
2697: }
2698: return(0);
2699: }
2701: /*@
2702: DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
2704: Not collective
2706: Input Parameter:
2707: . mesh - The DMPlex
2709: Output Parameter:
2711: Note:
2712: This should be called after all calls to DMPlexSetCone()
2714: Level: beginner
2716: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2717: @*/
2718: PetscErrorCode DMPlexSymmetrize(DM dm)
2719: {
2720: DM_Plex *mesh = (DM_Plex*) dm->data;
2721: PetscInt *offsets;
2722: PetscInt supportSize;
2723: PetscInt pStart, pEnd, p;
2728: if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2729: PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);
2730: /* Calculate support sizes */
2731: DMPlexGetChart(dm, &pStart, &pEnd);
2732: for (p = pStart; p < pEnd; ++p) {
2733: PetscInt dof, off, c;
2735: PetscSectionGetDof(mesh->coneSection, p, &dof);
2736: PetscSectionGetOffset(mesh->coneSection, p, &off);
2737: for (c = off; c < off+dof; ++c) {
2738: PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2739: }
2740: }
2741: for (p = pStart; p < pEnd; ++p) {
2742: PetscInt dof;
2744: PetscSectionGetDof(mesh->supportSection, p, &dof);
2746: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2747: }
2748: PetscSectionSetUp(mesh->supportSection);
2749: /* Calculate supports */
2750: PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2751: PetscMalloc1(supportSize, &mesh->supports);
2752: PetscCalloc1(pEnd - pStart, &offsets);
2753: for (p = pStart; p < pEnd; ++p) {
2754: PetscInt dof, off, c;
2756: PetscSectionGetDof(mesh->coneSection, p, &dof);
2757: PetscSectionGetOffset(mesh->coneSection, p, &off);
2758: for (c = off; c < off+dof; ++c) {
2759: const PetscInt q = mesh->cones[c];
2760: PetscInt offS;
2762: PetscSectionGetOffset(mesh->supportSection, q, &offS);
2764: mesh->supports[offS+offsets[q]] = p;
2765: ++offsets[q];
2766: }
2767: }
2768: PetscFree(offsets);
2769: PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);
2770: return(0);
2771: }
2773: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
2774: {
2775: IS stratumIS;
2779: if (pStart >= pEnd) return(0);
2780: #if defined(PETSC_USE_DEBUG)
2781: {
2782: PetscInt qStart, qEnd, numLevels, level;
2783: PetscBool overlap = PETSC_FALSE;
2784: DMLabelGetNumValues(label, &numLevels);
2785: for (level = 0; level < numLevels; level++) {
2786: DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2787: if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
2788: }
2789: if (overlap) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %D range [%D,%D) overlaps with depth %D range [%D,%D)", depth, pStart, pEnd, level, qStart, qEnd);
2790: }
2791: #endif
2792: ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);
2793: DMLabelSetStratumIS(label, depth, stratumIS);
2794: ISDestroy(&stratumIS);
2795: return(0);
2796: }
2798: static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt);
2800: /*@
2801: DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
2802: can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2803: same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2804: the DAG.
2806: Collective on dm
2808: Input Parameter:
2809: . mesh - The DMPlex
2811: Output Parameter:
2813: Notes:
2814: Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2815: 1 for edges, and so on. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2816: manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed
2817: via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1.
2819: DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
2821: Level: beginner
2823: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2824: @*/
2825: PetscErrorCode DMPlexStratify(DM dm)
2826: {
2827: DM_Plex *mesh = (DM_Plex*) dm->data;
2828: DMLabel label;
2829: PetscInt pStart, pEnd, p;
2830: PetscInt numRoots = 0, numLeaves = 0;
2831: PetscInt cMax, fMax, eMax, vMax;
2836: PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2838: /* Create depth label */
2839: DMPlexGetChart(dm, &pStart, &pEnd);
2840: DMCreateLabel(dm, "depth");
2841: DMPlexGetDepthLabel(dm, &label);
2843: {
2844: /* Initialize roots and count leaves */
2845: PetscInt sMin = PETSC_MAX_INT;
2846: PetscInt sMax = PETSC_MIN_INT;
2847: PetscInt coneSize, supportSize;
2849: for (p = pStart; p < pEnd; ++p) {
2850: DMPlexGetConeSize(dm, p, &coneSize);
2851: DMPlexGetSupportSize(dm, p, &supportSize);
2852: if (!coneSize && supportSize) {
2853: sMin = PetscMin(p, sMin);
2854: sMax = PetscMax(p, sMax);
2855: ++numRoots;
2856: } else if (!supportSize && coneSize) {
2857: ++numLeaves;
2858: } else if (!supportSize && !coneSize) {
2859: /* Isolated points */
2860: sMin = PetscMin(p, sMin);
2861: sMax = PetscMax(p, sMax);
2862: }
2863: }
2864: DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);
2865: }
2867: if (numRoots + numLeaves == (pEnd - pStart)) {
2868: PetscInt sMin = PETSC_MAX_INT;
2869: PetscInt sMax = PETSC_MIN_INT;
2870: PetscInt coneSize, supportSize;
2872: for (p = pStart; p < pEnd; ++p) {
2873: DMPlexGetConeSize(dm, p, &coneSize);
2874: DMPlexGetSupportSize(dm, p, &supportSize);
2875: if (!supportSize && coneSize) {
2876: sMin = PetscMin(p, sMin);
2877: sMax = PetscMax(p, sMax);
2878: }
2879: }
2880: DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);
2881: } else {
2882: PetscInt level = 0;
2883: PetscInt qStart, qEnd, q;
2885: DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2886: while (qEnd > qStart) {
2887: PetscInt sMin = PETSC_MAX_INT;
2888: PetscInt sMax = PETSC_MIN_INT;
2890: for (q = qStart; q < qEnd; ++q) {
2891: const PetscInt *support;
2892: PetscInt supportSize, s;
2894: DMPlexGetSupportSize(dm, q, &supportSize);
2895: DMPlexGetSupport(dm, q, &support);
2896: for (s = 0; s < supportSize; ++s) {
2897: sMin = PetscMin(support[s], sMin);
2898: sMax = PetscMax(support[s], sMax);
2899: }
2900: }
2901: DMLabelGetNumValues(label, &level);
2902: DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);
2903: DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2904: }
2905: }
2906: { /* just in case there is an empty process */
2907: PetscInt numValues, maxValues = 0, v;
2909: DMLabelGetNumValues(label, &numValues);
2910: MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2911: for (v = numValues; v < maxValues; v++) {
2912: DMLabelAddStratum(label, v);
2913: }
2914: }
2915: PetscObjectStateGet((PetscObject) label, &mesh->depthState);
2917: DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2918: if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2919: PetscInt dim;
2920: DMLabel dimLabel;
2922: DMGetDimension(dm, &dim);
2923: DMCreateLabel(dm, "dim");
2924: DMGetLabel(dm, "dim", &dimLabel);
2925: if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2926: if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2927: if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2928: if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2929: }
2930: PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2931: return(0);
2932: }
2934: /*@C
2935: DMPlexGetJoin - Get an array for the join of the set of points
2937: Not Collective
2939: Input Parameters:
2940: + dm - The DMPlex object
2941: . numPoints - The number of input points for the join
2942: - points - The input points
2944: Output Parameters:
2945: + numCoveredPoints - The number of points in the join
2946: - coveredPoints - The points in the join
2948: Level: intermediate
2950: Note: Currently, this is restricted to a single level join
2952: Fortran Notes:
2953: Since it returns an array, this routine is only available in Fortran 90, and you must
2954: include petsc.h90 in your code.
2956: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2958: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2959: @*/
2960: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2961: {
2962: DM_Plex *mesh = (DM_Plex*) dm->data;
2963: PetscInt *join[2];
2964: PetscInt joinSize, i = 0;
2965: PetscInt dof, off, p, c, m;
2973: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2974: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2975: /* Copy in support of first point */
2976: PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2977: PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2978: for (joinSize = 0; joinSize < dof; ++joinSize) {
2979: join[i][joinSize] = mesh->supports[off+joinSize];
2980: }
2981: /* Check each successive support */
2982: for (p = 1; p < numPoints; ++p) {
2983: PetscInt newJoinSize = 0;
2985: PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2986: PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2987: for (c = 0; c < dof; ++c) {
2988: const PetscInt point = mesh->supports[off+c];
2990: for (m = 0; m < joinSize; ++m) {
2991: if (point == join[i][m]) {
2992: join[1-i][newJoinSize++] = point;
2993: break;
2994: }
2995: }
2996: }
2997: joinSize = newJoinSize;
2998: i = 1-i;
2999: }
3000: *numCoveredPoints = joinSize;
3001: *coveredPoints = join[i];
3002: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3003: return(0);
3004: }
3006: /*@C
3007: DMPlexRestoreJoin - Restore an array for the join of the set of points
3009: Not Collective
3011: Input Parameters:
3012: + dm - The DMPlex object
3013: . numPoints - The number of input points for the join
3014: - points - The input points
3016: Output Parameters:
3017: + numCoveredPoints - The number of points in the join
3018: - coveredPoints - The points in the join
3020: Fortran Notes:
3021: Since it returns an array, this routine is only available in Fortran 90, and you must
3022: include petsc.h90 in your code.
3024: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3026: Level: intermediate
3028: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
3029: @*/
3030: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3031: {
3039: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3040: if (numCoveredPoints) *numCoveredPoints = 0;
3041: return(0);
3042: }
3044: /*@C
3045: DMPlexGetFullJoin - Get an array for the join of the set of points
3047: Not Collective
3049: Input Parameters:
3050: + dm - The DMPlex object
3051: . numPoints - The number of input points for the join
3052: - points - The input points
3054: Output Parameters:
3055: + numCoveredPoints - The number of points in the join
3056: - coveredPoints - The points in the join
3058: Fortran Notes:
3059: Since it returns an array, this routine is only available in Fortran 90, and you must
3060: include petsc.h90 in your code.
3062: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3064: Level: intermediate
3066: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
3067: @*/
3068: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3069: {
3070: DM_Plex *mesh = (DM_Plex*) dm->data;
3071: PetscInt *offsets, **closures;
3072: PetscInt *join[2];
3073: PetscInt depth = 0, maxSize, joinSize = 0, i = 0;
3074: PetscInt p, d, c, m, ms;
3083: DMPlexGetDepth(dm, &depth);
3084: PetscCalloc1(numPoints, &closures);
3085: DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3086: ms = mesh->maxSupportSize;
3087: maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
3088: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
3089: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);
3091: for (p = 0; p < numPoints; ++p) {
3092: PetscInt closureSize;
3094: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);
3096: offsets[p*(depth+2)+0] = 0;
3097: for (d = 0; d < depth+1; ++d) {
3098: PetscInt pStart, pEnd, i;
3100: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
3101: for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
3102: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3103: offsets[p*(depth+2)+d+1] = i;
3104: break;
3105: }
3106: }
3107: if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
3108: }
3109: 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);
3110: }
3111: for (d = 0; d < depth+1; ++d) {
3112: PetscInt dof;
3114: /* Copy in support of first point */
3115: dof = offsets[d+1] - offsets[d];
3116: for (joinSize = 0; joinSize < dof; ++joinSize) {
3117: join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
3118: }
3119: /* Check each successive cone */
3120: for (p = 1; p < numPoints && joinSize; ++p) {
3121: PetscInt newJoinSize = 0;
3123: dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
3124: for (c = 0; c < dof; ++c) {
3125: const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
3127: for (m = 0; m < joinSize; ++m) {
3128: if (point == join[i][m]) {
3129: join[1-i][newJoinSize++] = point;
3130: break;
3131: }
3132: }
3133: }
3134: joinSize = newJoinSize;
3135: i = 1-i;
3136: }
3137: if (joinSize) break;
3138: }
3139: *numCoveredPoints = joinSize;
3140: *coveredPoints = join[i];
3141: for (p = 0; p < numPoints; ++p) {
3142: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
3143: }
3144: PetscFree(closures);
3145: DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3146: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3147: return(0);
3148: }
3150: /*@C
3151: DMPlexGetMeet - Get an array for the meet of the set of points
3153: Not Collective
3155: Input Parameters:
3156: + dm - The DMPlex object
3157: . numPoints - The number of input points for the meet
3158: - points - The input points
3160: Output Parameters:
3161: + numCoveredPoints - The number of points in the meet
3162: - coveredPoints - The points in the meet
3164: Level: intermediate
3166: Note: Currently, this is restricted to a single level meet
3168: Fortran Notes:
3169: Since it returns an array, this routine is only available in Fortran 90, and you must
3170: include petsc.h90 in your code.
3172: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3174: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
3175: @*/
3176: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
3177: {
3178: DM_Plex *mesh = (DM_Plex*) dm->data;
3179: PetscInt *meet[2];
3180: PetscInt meetSize, i = 0;
3181: PetscInt dof, off, p, c, m;
3189: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
3190: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
3191: /* Copy in cone of first point */
3192: PetscSectionGetDof(mesh->coneSection, points[0], &dof);
3193: PetscSectionGetOffset(mesh->coneSection, points[0], &off);
3194: for (meetSize = 0; meetSize < dof; ++meetSize) {
3195: meet[i][meetSize] = mesh->cones[off+meetSize];
3196: }
3197: /* Check each successive cone */
3198: for (p = 1; p < numPoints; ++p) {
3199: PetscInt newMeetSize = 0;
3201: PetscSectionGetDof(mesh->coneSection, points[p], &dof);
3202: PetscSectionGetOffset(mesh->coneSection, points[p], &off);
3203: for (c = 0; c < dof; ++c) {
3204: const PetscInt point = mesh->cones[off+c];
3206: for (m = 0; m < meetSize; ++m) {
3207: if (point == meet[i][m]) {
3208: meet[1-i][newMeetSize++] = point;
3209: break;
3210: }
3211: }
3212: }
3213: meetSize = newMeetSize;
3214: i = 1-i;
3215: }
3216: *numCoveringPoints = meetSize;
3217: *coveringPoints = meet[i];
3218: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3219: return(0);
3220: }
3222: /*@C
3223: DMPlexRestoreMeet - Restore an array for the meet of the set of points
3225: Not Collective
3227: Input Parameters:
3228: + dm - The DMPlex object
3229: . numPoints - The number of input points for the meet
3230: - points - The input points
3232: Output Parameters:
3233: + numCoveredPoints - The number of points in the meet
3234: - coveredPoints - The points in the meet
3236: Level: intermediate
3238: Fortran Notes:
3239: Since it returns an array, this routine is only available in Fortran 90, and you must
3240: include petsc.h90 in your code.
3242: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3244: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
3245: @*/
3246: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3247: {
3255: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3256: if (numCoveredPoints) *numCoveredPoints = 0;
3257: return(0);
3258: }
3260: /*@C
3261: DMPlexGetFullMeet - Get an array for the meet of the set of points
3263: Not Collective
3265: Input Parameters:
3266: + dm - The DMPlex object
3267: . numPoints - The number of input points for the meet
3268: - points - The input points
3270: Output Parameters:
3271: + numCoveredPoints - The number of points in the meet
3272: - coveredPoints - The points in the meet
3274: Level: intermediate
3276: Fortran Notes:
3277: Since it returns an array, this routine is only available in Fortran 90, and you must
3278: include petsc.h90 in your code.
3280: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3282: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3283: @*/
3284: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3285: {
3286: DM_Plex *mesh = (DM_Plex*) dm->data;
3287: PetscInt *offsets, **closures;
3288: PetscInt *meet[2];
3289: PetscInt height = 0, maxSize, meetSize = 0, i = 0;
3290: PetscInt p, h, c, m, mc;
3299: DMPlexGetDepth(dm, &height);
3300: PetscMalloc1(numPoints, &closures);
3301: DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3302: mc = mesh->maxConeSize;
3303: maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3304: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3305: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);
3307: for (p = 0; p < numPoints; ++p) {
3308: PetscInt closureSize;
3310: DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);
3312: offsets[p*(height+2)+0] = 0;
3313: for (h = 0; h < height+1; ++h) {
3314: PetscInt pStart, pEnd, i;
3316: DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3317: for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3318: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3319: offsets[p*(height+2)+h+1] = i;
3320: break;
3321: }
3322: }
3323: if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3324: }
3325: 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);
3326: }
3327: for (h = 0; h < height+1; ++h) {
3328: PetscInt dof;
3330: /* Copy in cone of first point */
3331: dof = offsets[h+1] - offsets[h];
3332: for (meetSize = 0; meetSize < dof; ++meetSize) {
3333: meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3334: }
3335: /* Check each successive cone */
3336: for (p = 1; p < numPoints && meetSize; ++p) {
3337: PetscInt newMeetSize = 0;
3339: dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
3340: for (c = 0; c < dof; ++c) {
3341: const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
3343: for (m = 0; m < meetSize; ++m) {
3344: if (point == meet[i][m]) {
3345: meet[1-i][newMeetSize++] = point;
3346: break;
3347: }
3348: }
3349: }
3350: meetSize = newMeetSize;
3351: i = 1-i;
3352: }
3353: if (meetSize) break;
3354: }
3355: *numCoveredPoints = meetSize;
3356: *coveredPoints = meet[i];
3357: for (p = 0; p < numPoints; ++p) {
3358: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3359: }
3360: PetscFree(closures);
3361: DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3362: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3363: return(0);
3364: }
3366: /*@C
3367: DMPlexEqual - Determine if two DMs have the same topology
3369: Not Collective
3371: Input Parameters:
3372: + dmA - A DMPlex object
3373: - dmB - A DMPlex object
3375: Output Parameters:
3376: . equal - PETSC_TRUE if the topologies are identical
3378: Level: intermediate
3380: Notes:
3381: We are not solving graph isomorphism, so we do not permutation.
3383: .seealso: DMPlexGetCone()
3384: @*/
3385: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3386: {
3387: PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
3395: *equal = PETSC_FALSE;
3396: DMPlexGetDepth(dmA, &depth);
3397: DMPlexGetDepth(dmB, &depthB);
3398: if (depth != depthB) return(0);
3399: DMPlexGetChart(dmA, &pStart, &pEnd);
3400: DMPlexGetChart(dmB, &pStartB, &pEndB);
3401: if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3402: for (p = pStart; p < pEnd; ++p) {
3403: const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3404: PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s;
3406: DMPlexGetConeSize(dmA, p, &coneSize);
3407: DMPlexGetCone(dmA, p, &cone);
3408: DMPlexGetConeOrientation(dmA, p, &ornt);
3409: DMPlexGetConeSize(dmB, p, &coneSizeB);
3410: DMPlexGetCone(dmB, p, &coneB);
3411: DMPlexGetConeOrientation(dmB, p, &orntB);
3412: if (coneSize != coneSizeB) return(0);
3413: for (c = 0; c < coneSize; ++c) {
3414: if (cone[c] != coneB[c]) return(0);
3415: if (ornt[c] != orntB[c]) return(0);
3416: }
3417: DMPlexGetSupportSize(dmA, p, &supportSize);
3418: DMPlexGetSupport(dmA, p, &support);
3419: DMPlexGetSupportSize(dmB, p, &supportSizeB);
3420: DMPlexGetSupport(dmB, p, &supportB);
3421: if (supportSize != supportSizeB) return(0);
3422: for (s = 0; s < supportSize; ++s) {
3423: if (support[s] != supportB[s]) return(0);
3424: }
3425: }
3426: *equal = PETSC_TRUE;
3427: return(0);
3428: }
3430: /*@C
3431: DMPlexGetNumFaceVertices - Returns the number of vertices on a face
3433: Not Collective
3435: Input Parameters:
3436: + dm - The DMPlex
3437: . cellDim - The cell dimension
3438: - numCorners - The number of vertices on a cell
3440: Output Parameters:
3441: . numFaceVertices - The number of vertices on a face
3443: Level: developer
3445: Notes:
3446: Of course this can only work for a restricted set of symmetric shapes
3448: .seealso: DMPlexGetCone()
3449: @*/
3450: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3451: {
3452: MPI_Comm comm;
3456: PetscObjectGetComm((PetscObject)dm,&comm);
3458: switch (cellDim) {
3459: case 0:
3460: *numFaceVertices = 0;
3461: break;
3462: case 1:
3463: *numFaceVertices = 1;
3464: break;
3465: case 2:
3466: switch (numCorners) {
3467: case 3: /* triangle */
3468: *numFaceVertices = 2; /* Edge has 2 vertices */
3469: break;
3470: case 4: /* quadrilateral */
3471: *numFaceVertices = 2; /* Edge has 2 vertices */
3472: break;
3473: case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3474: *numFaceVertices = 3; /* Edge has 3 vertices */
3475: break;
3476: case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3477: *numFaceVertices = 3; /* Edge has 3 vertices */
3478: break;
3479: default:
3480: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3481: }
3482: break;
3483: case 3:
3484: switch (numCorners) {
3485: case 4: /* tetradehdron */
3486: *numFaceVertices = 3; /* Face has 3 vertices */
3487: break;
3488: case 6: /* tet cohesive cells */
3489: *numFaceVertices = 4; /* Face has 4 vertices */
3490: break;
3491: case 8: /* hexahedron */
3492: *numFaceVertices = 4; /* Face has 4 vertices */
3493: break;
3494: case 9: /* tet cohesive Lagrange cells */
3495: *numFaceVertices = 6; /* Face has 6 vertices */
3496: break;
3497: case 10: /* quadratic tetrahedron */
3498: *numFaceVertices = 6; /* Face has 6 vertices */
3499: break;
3500: case 12: /* hex cohesive Lagrange cells */
3501: *numFaceVertices = 6; /* Face has 6 vertices */
3502: break;
3503: case 18: /* quadratic tet cohesive Lagrange cells */
3504: *numFaceVertices = 6; /* Face has 6 vertices */
3505: break;
3506: case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3507: *numFaceVertices = 9; /* Face has 9 vertices */
3508: break;
3509: default:
3510: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3511: }
3512: break;
3513: default:
3514: SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3515: }
3516: return(0);
3517: }
3519: /*@
3520: DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
3522: Not Collective
3524: Input Parameter:
3525: . dm - The DMPlex object
3527: Output Parameter:
3528: . depthLabel - The DMLabel recording point depth
3530: Level: developer
3532: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3533: @*/
3534: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3535: {
3541: if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3542: *depthLabel = dm->depthLabel;
3543: return(0);
3544: }
3546: /*@
3547: DMPlexGetDepth - Get the depth of the DAG representing this mesh
3549: Not Collective
3551: Input Parameter:
3552: . dm - The DMPlex object
3554: Output Parameter:
3555: . depth - The number of strata (breadth first levels) in the DAG
3557: Level: developer
3559: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3560: @*/
3561: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3562: {
3563: DMLabel label;
3564: PetscInt d = 0;
3570: DMPlexGetDepthLabel(dm, &label);
3571: if (label) {DMLabelGetNumValues(label, &d);}
3572: *depth = d-1;
3573: return(0);
3574: }
3576: /*@
3577: DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
3579: Not Collective
3581: Input Parameters:
3582: + dm - The DMPlex object
3583: - stratumValue - The requested depth
3585: Output Parameters:
3586: + start - The first point at this depth
3587: - end - One beyond the last point at this depth
3589: Notes:
3590: Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points,
3591: often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
3592: higher dimension, e.g., "edges".
3594: Level: developer
3596: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3597: @*/
3598: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3599: {
3600: DMLabel label;
3601: PetscInt pStart, pEnd;
3608: DMPlexGetChart(dm, &pStart, &pEnd);
3609: if (pStart == pEnd) return(0);
3610: if (stratumValue < 0) {
3611: if (start) *start = pStart;
3612: if (end) *end = pEnd;
3613: return(0);
3614: }
3615: DMPlexGetDepthLabel(dm, &label);
3616: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3617: DMLabelGetStratumBounds(label, stratumValue, start, end);
3618: return(0);
3619: }
3621: /*@
3622: DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3624: Not Collective
3626: Input Parameters:
3627: + dm - The DMPlex object
3628: - stratumValue - The requested height
3630: Output Parameters:
3631: + start - The first point at this height
3632: - end - One beyond the last point at this height
3634: Notes:
3635: Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension
3636: points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height
3637: stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
3639: Level: developer
3641: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3642: @*/
3643: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3644: {
3645: DMLabel label;
3646: PetscInt depth, pStart, pEnd;
3653: DMPlexGetChart(dm, &pStart, &pEnd);
3654: if (pStart == pEnd) return(0);
3655: if (stratumValue < 0) {
3656: if (start) *start = pStart;
3657: if (end) *end = pEnd;
3658: return(0);
3659: }
3660: DMPlexGetDepthLabel(dm, &label);
3661: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3662: DMLabelGetNumValues(label, &depth);
3663: DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3664: return(0);
3665: }
3667: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3668: {
3669: PetscSection section, s;
3670: Mat m;
3671: PetscInt maxHeight;
3675: DMClone(dm, cdm);
3676: DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3677: DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3678: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
3679: DMSetLocalSection(*cdm, section);
3680: PetscSectionDestroy(§ion);
3681: PetscSectionCreate(PETSC_COMM_SELF, &s);
3682: MatCreate(PETSC_COMM_SELF, &m);
3683: DMSetDefaultConstraints(*cdm, s, m);
3684: PetscSectionDestroy(&s);
3685: MatDestroy(&m);
3687: DMSetNumFields(*cdm, 1);
3688: DMCreateDS(*cdm);
3689: return(0);
3690: }
3692: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3693: {
3694: Vec coordsLocal;
3695: DM coordsDM;
3699: *field = NULL;
3700: DMGetCoordinatesLocal(dm,&coordsLocal);
3701: DMGetCoordinateDM(dm,&coordsDM);
3702: if (coordsLocal && coordsDM) {
3703: DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3704: }
3705: return(0);
3706: }
3708: /*@C
3709: DMPlexGetConeSection - Return a section which describes the layout of cone data
3711: Not Collective
3713: Input Parameters:
3714: . dm - The DMPlex object
3716: Output Parameter:
3717: . section - The PetscSection object
3719: Level: developer
3721: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3722: @*/
3723: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3724: {
3725: DM_Plex *mesh = (DM_Plex*) dm->data;
3729: if (section) *section = mesh->coneSection;
3730: return(0);
3731: }
3733: /*@C
3734: DMPlexGetSupportSection - Return a section which describes the layout of support data
3736: Not Collective
3738: Input Parameters:
3739: . dm - The DMPlex object
3741: Output Parameter:
3742: . section - The PetscSection object
3744: Level: developer
3746: .seealso: DMPlexGetConeSection()
3747: @*/
3748: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3749: {
3750: DM_Plex *mesh = (DM_Plex*) dm->data;
3754: if (section) *section = mesh->supportSection;
3755: return(0);
3756: }
3758: /*@C
3759: DMPlexGetCones - Return cone data
3761: Not Collective
3763: Input Parameters:
3764: . dm - The DMPlex object
3766: Output Parameter:
3767: . cones - The cone for each point
3769: Level: developer
3771: .seealso: DMPlexGetConeSection()
3772: @*/
3773: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3774: {
3775: DM_Plex *mesh = (DM_Plex*) dm->data;
3779: if (cones) *cones = mesh->cones;
3780: return(0);
3781: }
3783: /*@C
3784: DMPlexGetConeOrientations - Return cone orientation data
3786: Not Collective
3788: Input Parameters:
3789: . dm - The DMPlex object
3791: Output Parameter:
3792: . coneOrientations - The cone orientation for each point
3794: Level: developer
3796: .seealso: DMPlexGetConeSection()
3797: @*/
3798: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3799: {
3800: DM_Plex *mesh = (DM_Plex*) dm->data;
3804: if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3805: return(0);
3806: }
3808: /******************************** FEM Support **********************************/
3810: /*
3811: Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point
3812: representing a line in the section.
3813: */
3814: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
3815: {
3819: PetscSectionGetFieldComponents(section, field, Nc);
3820: if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */
3821: *k = 1;
3822: } else { /* Assume the full interpolated mesh is in the chart; lines in particular */
3823: /* An order k SEM disc has k-1 dofs on an edge */
3824: PetscSectionGetFieldDof(section, line, field, k);
3825: *k = *k / *Nc + 1;
3826: }
3827: return(0);
3828: }
3830: /*@
3832: DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
3833: lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
3834: section provided (or the section of the DM).
3836: Input Parameters:
3837: + dm - The DM
3838: . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
3839: - section - The PetscSection to reorder, or NULL for the default section
3841: Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
3842: degree of the basis.
3844: Example:
3845: A typical interpolated single-quad mesh might order points as
3846: .vb
3847: [c0, v1, v2, v3, v4, e5, e6, e7, e8]
3849: v4 -- e6 -- v3
3850: | |
3851: e7 c0 e8
3852: | |
3853: v1 -- e5 -- v2
3854: .ve
3856: (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign
3857: dofs in the order of points, e.g.,
3858: .vb
3859: c0 -> [0,1,2,3]
3860: v1 -> [4]
3861: ...
3862: e5 -> [8, 9]
3863: .ve
3865: which corresponds to the dofs
3866: .vb
3867: 6 10 11 7
3868: 13 2 3 15
3869: 12 0 1 14
3870: 4 8 9 5
3871: .ve
3873: The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
3874: .vb
3875: 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
3876: .ve
3878: After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
3879: .vb
3880: 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
3881: .ve
3883: Level: developer
3885: .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlocalSection()
3886: @*/
3887: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
3888: {
3889: DMLabel label;
3890: PetscInt *perm;
3891: PetscInt dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3892: PetscBool vertexchart;
3896: if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3897: DMGetDimension(dm, &dim);
3898: DMPlexGetDepthLabel(dm, &label);
3899: DMLabelGetValue(label, point, &depth);
3900: if (depth == 1) {eStart = point;}
3901: else if (depth == dim) {
3902: const PetscInt *cone;
3904: DMPlexGetCone(dm, point, &cone);
3905: if (dim == 2) eStart = cone[0];
3906: else if (dim == 3) {
3907: const PetscInt *cone2;
3908: DMPlexGetCone(dm, cone[0], &cone2);
3909: eStart = cone2[0];
3910: } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim);
3911: } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim);
3912: if (!section) {DMGetLocalSection(dm, §ion);}
3913: { /* Determine whether the chart covers all points or just vertices. */
3914: PetscInt pStart,pEnd,cStart,cEnd;
3915: DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);
3916: PetscSectionGetChart(section,&cStart,&cEnd);
3917: if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
3918: else vertexchart = PETSC_FALSE; /* Assume all interpolated points are in chart */
3919: }
3920: PetscSectionGetNumFields(section, &Nf);
3921: if (dim < 1) return(0);
3922: for (f = 0; f < Nf; ++f) {
3923: PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3924: size += PetscPowInt(k+1, dim)*Nc;
3925: }
3926: PetscMalloc1(size, &perm);
3927: for (f = 0; f < Nf; ++f) {
3928: switch (dim) {
3929: case 1:
3930: PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3931: /*
3932: Original ordering is [ edge of length k-1; vtx0; vtx1 ]
3933: We want [ vtx0; edge of length k-1; vtx1 ]
3934: */
3935: for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
3936: for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
3937: for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
3938: foffset = offset;
3939: break;
3940: case 2:
3941: /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3942: PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3943: /* The SEM order is
3945: v_lb, {e_b}, v_rb,
3946: e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3947: v_lt, reverse {e_t}, v_rt
3948: */
3949: {
3950: const PetscInt of = 0;
3951: const PetscInt oeb = of + PetscSqr(k-1);
3952: const PetscInt oer = oeb + (k-1);
3953: const PetscInt oet = oer + (k-1);
3954: const PetscInt oel = oet + (k-1);
3955: const PetscInt ovlb = oel + (k-1);
3956: const PetscInt ovrb = ovlb + 1;
3957: const PetscInt ovrt = ovrb + 1;
3958: const PetscInt ovlt = ovrt + 1;
3959: PetscInt o;
3961: /* bottom */
3962: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3963: for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3964: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3965: /* middle */
3966: for (i = 0; i < k-1; ++i) {
3967: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3968: for (o = of+(k-1)*i; o < of+(k-1)*(i+1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3969: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3970: }
3971: /* top */
3972: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3973: for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3974: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3975: foffset = offset;
3976: }
3977: break;
3978: case 3:
3979: /* The original hex closure is
3981: {c,
3982: f_b, f_t, f_f, f_b, f_r, f_l,
3983: e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb,
3984: v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3985: */
3986: PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3987: /* The SEM order is
3988: Bottom Slice
3989: v_blf, {e^{(k-1)-n}_bf}, v_brf,
3990: e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3991: v_blb, {e_bb}, v_brb,
3993: Middle Slice (j)
3994: {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3995: f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3996: e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3998: Top Slice
3999: v_tlf, {e_tf}, v_trf,
4000: e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
4001: v_tlb, {e^{(k-1)-n}_tb}, v_trb,
4002: */
4003: {
4004: const PetscInt oc = 0;
4005: const PetscInt ofb = oc + PetscSqr(k-1)*(k-1);
4006: const PetscInt oft = ofb + PetscSqr(k-1);
4007: const PetscInt off = oft + PetscSqr(k-1);
4008: const PetscInt ofk = off + PetscSqr(k-1);
4009: const PetscInt ofr = ofk + PetscSqr(k-1);
4010: const PetscInt ofl = ofr + PetscSqr(k-1);
4011: const PetscInt oebl = ofl + PetscSqr(k-1);
4012: const PetscInt oebb = oebl + (k-1);
4013: const PetscInt oebr = oebb + (k-1);
4014: const PetscInt oebf = oebr + (k-1);
4015: const PetscInt oetf = oebf + (k-1);
4016: const PetscInt oetr = oetf + (k-1);
4017: const PetscInt oetb = oetr + (k-1);
4018: const PetscInt oetl = oetb + (k-1);
4019: const PetscInt oerf = oetl + (k-1);
4020: const PetscInt oelf = oerf + (k-1);
4021: const PetscInt oelb = oelf + (k-1);
4022: const PetscInt oerb = oelb + (k-1);
4023: const PetscInt ovblf = oerb + (k-1);
4024: const PetscInt ovblb = ovblf + 1;
4025: const PetscInt ovbrb = ovblb + 1;
4026: const PetscInt ovbrf = ovbrb + 1;
4027: const PetscInt ovtlf = ovbrf + 1;
4028: const PetscInt ovtrf = ovtlf + 1;
4029: const PetscInt ovtrb = ovtrf + 1;
4030: const PetscInt ovtlb = ovtrb + 1;
4031: PetscInt o, n;
4033: /* Bottom Slice */
4034: /* bottom */
4035: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
4036: for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4037: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
4038: /* middle */
4039: for (i = 0; i < k-1; ++i) {
4040: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
4041: for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;}
4042: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
4043: }
4044: /* top */
4045: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
4046: for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4047: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
4049: /* Middle Slice */
4050: for (j = 0; j < k-1; ++j) {
4051: /* bottom */
4052: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
4053: for (o = off+j*(k-1); o < off+(j+1)*(k-1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4054: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
4055: /* middle */
4056: for (i = 0; i < k-1; ++i) {
4057: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
4058: for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc+(j*(k-1)+i)*(k-1)+n)*Nc + c + foffset;
4059: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
4060: }
4061: /* top */
4062: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
4063: for (o = ofk+j*(k-1)+(k-2); o >= ofk+j*(k-1); --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4064: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
4065: }
4067: /* Top Slice */
4068: /* bottom */
4069: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
4070: for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4071: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
4072: /* middle */
4073: for (i = 0; i < k-1; ++i) {
4074: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
4075: for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
4076: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
4077: }
4078: /* top */
4079: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
4080: for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4081: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
4083: foffset = offset;
4084: }
4085: break;
4086: default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
4087: }
4088: }
4089: if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
4090: /* Check permutation */
4091: {
4092: PetscInt *check;
4094: PetscMalloc1(size, &check);
4095: for (i = 0; i < size; ++i) {check[i] = -1; if (perm[i] < 0 || perm[i] >= size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%D] = %D", i, perm[i]);}
4096: for (i = 0; i < size; ++i) check[perm[i]] = i;
4097: for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
4098: PetscFree(check);
4099: }
4100: PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
4101: return(0);
4102: }
4104: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
4105: {
4106: PetscDS prob;
4107: PetscInt depth, Nf, h;
4108: DMLabel label;
4112: DMGetDS(dm, &prob);
4113: Nf = prob->Nf;
4114: label = dm->depthLabel;
4115: *dspace = NULL;
4116: if (field < Nf) {
4117: PetscObject disc = prob->disc[field];
4119: if (disc->classid == PETSCFE_CLASSID) {
4120: PetscDualSpace dsp;
4122: PetscFEGetDualSpace((PetscFE)disc,&dsp);
4123: DMLabelGetNumValues(label,&depth);
4124: DMLabelGetValue(label,point,&h);
4125: h = depth - 1 - h;
4126: if (h) {
4127: PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
4128: } else {
4129: *dspace = dsp;
4130: }
4131: }
4132: }
4133: return(0);
4134: }
4137: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4138: {
4139: PetscScalar *array, *vArray;
4140: const PetscInt *cone, *coneO;
4141: PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0;
4142: PetscErrorCode ierr;
4145: PetscSectionGetChart(section, &pStart, &pEnd);
4146: DMPlexGetConeSize(dm, point, &numPoints);
4147: DMPlexGetCone(dm, point, &cone);
4148: DMPlexGetConeOrientation(dm, point, &coneO);
4149: if (!values || !*values) {
4150: if ((point >= pStart) && (point < pEnd)) {
4151: PetscInt dof;
4153: PetscSectionGetDof(section, point, &dof);
4154: size += dof;
4155: }
4156: for (p = 0; p < numPoints; ++p) {
4157: const PetscInt cp = cone[p];
4158: PetscInt dof;
4160: if ((cp < pStart) || (cp >= pEnd)) continue;
4161: PetscSectionGetDof(section, cp, &dof);
4162: size += dof;
4163: }
4164: if (!values) {
4165: if (csize) *csize = size;
4166: return(0);
4167: }
4168: DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
4169: } else {
4170: array = *values;
4171: }
4172: size = 0;
4173: VecGetArray(v, &vArray);
4174: if ((point >= pStart) && (point < pEnd)) {
4175: PetscInt dof, off, d;
4176: PetscScalar *varr;
4178: PetscSectionGetDof(section, point, &dof);
4179: PetscSectionGetOffset(section, point, &off);
4180: varr = &vArray[off];
4181: for (d = 0; d < dof; ++d, ++offset) {
4182: array[offset] = varr[d];
4183: }
4184: size += dof;
4185: }
4186: for (p = 0; p < numPoints; ++p) {
4187: const PetscInt cp = cone[p];
4188: PetscInt o = coneO[p];
4189: PetscInt dof, off, d;
4190: PetscScalar *varr;
4192: if ((cp < pStart) || (cp >= pEnd)) continue;
4193: PetscSectionGetDof(section, cp, &dof);
4194: PetscSectionGetOffset(section, cp, &off);
4195: varr = &vArray[off];
4196: if (o >= 0) {
4197: for (d = 0; d < dof; ++d, ++offset) {
4198: array[offset] = varr[d];
4199: }
4200: } else {
4201: for (d = dof-1; d >= 0; --d, ++offset) {
4202: array[offset] = varr[d];
4203: }
4204: }
4205: size += dof;
4206: }
4207: VecRestoreArray(v, &vArray);
4208: if (!*values) {
4209: if (csize) *csize = size;
4210: *values = array;
4211: } else {
4212: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4213: *csize = size;
4214: }
4215: return(0);
4216: }
4218: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4219: {
4220: const PetscInt *cla;
4221: PetscInt np, *pts = NULL;
4225: PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
4226: if (!*clPoints) {
4227: PetscInt pStart, pEnd, p, q;
4229: PetscSectionGetChart(section, &pStart, &pEnd);
4230: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
4231: /* Compress out points not in the section */
4232: for (p = 0, q = 0; p < np; p++) {
4233: PetscInt r = pts[2*p];
4234: if ((r >= pStart) && (r < pEnd)) {
4235: pts[q*2] = r;
4236: pts[q*2+1] = pts[2*p+1];
4237: ++q;
4238: }
4239: }
4240: np = q;
4241: cla = NULL;
4242: } else {
4243: PetscInt dof, off;
4245: PetscSectionGetDof(*clSec, point, &dof);
4246: PetscSectionGetOffset(*clSec, point, &off);
4247: ISGetIndices(*clPoints, &cla);
4248: np = dof/2;
4249: pts = (PetscInt *) &cla[off];
4250: }
4251: *numPoints = np;
4252: *points = pts;
4253: *clp = cla;
4255: return(0);
4256: }
4258: PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4259: {
4263: if (!*clPoints) {
4264: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
4265: } else {
4266: ISRestoreIndices(*clPoints, clp);
4267: }
4268: *numPoints = 0;
4269: *points = NULL;
4270: *clSec = NULL;
4271: *clPoints = NULL;
4272: *clp = NULL;
4273: return(0);
4274: }
4276: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
4277: {
4278: PetscInt offset = 0, p;
4279: const PetscInt **perms = NULL;
4280: const PetscScalar **flips = NULL;
4281: PetscErrorCode ierr;
4284: *size = 0;
4285: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4286: for (p = 0; p < numPoints; p++) {
4287: const PetscInt point = points[2*p];
4288: const PetscInt *perm = perms ? perms[p] : NULL;
4289: const PetscScalar *flip = flips ? flips[p] : NULL;
4290: PetscInt dof, off, d;
4291: const PetscScalar *varr;
4293: PetscSectionGetDof(section, point, &dof);
4294: PetscSectionGetOffset(section, point, &off);
4295: varr = &vArray[off];
4296: if (clperm) {
4297: if (perm) {
4298: for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
4299: } else {
4300: for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d];
4301: }
4302: if (flip) {
4303: for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d];
4304: }
4305: } else {
4306: if (perm) {
4307: for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
4308: } else {
4309: for (d = 0; d < dof; d++) array[offset + d ] = varr[d];
4310: }
4311: if (flip) {
4312: for (d = 0; d < dof; d++) array[offset + d ] *= flip[d];
4313: }
4314: }
4315: offset += dof;
4316: }
4317: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4318: *size = offset;
4319: return(0);
4320: }
4322: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
4323: {
4324: PetscInt offset = 0, f;
4325: PetscErrorCode ierr;
4328: *size = 0;
4329: for (f = 0; f < numFields; ++f) {
4330: PetscInt p;
4331: const PetscInt **perms = NULL;
4332: const PetscScalar **flips = NULL;
4334: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4335: for (p = 0; p < numPoints; p++) {
4336: const PetscInt point = points[2*p];
4337: PetscInt fdof, foff, b;
4338: const PetscScalar *varr;
4339: const PetscInt *perm = perms ? perms[p] : NULL;
4340: const PetscScalar *flip = flips ? flips[p] : NULL;
4342: PetscSectionGetFieldDof(section, point, f, &fdof);
4343: PetscSectionGetFieldOffset(section, point, f, &foff);
4344: varr = &vArray[foff];
4345: if (clperm) {
4346: if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}}
4347: else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}}
4348: if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}}
4349: } else {
4350: if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}}
4351: else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}}
4352: if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}}
4353: }
4354: offset += fdof;
4355: }
4356: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4357: }
4358: *size = offset;
4359: return(0);
4360: }
4362: /*@C
4363: DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4365: Not collective
4367: Input Parameters:
4368: + dm - The DM
4369: . section - The section describing the layout in v, or NULL to use the default section
4370: . v - The local vector
4371: . point - The point in the DM
4372: . csize - The size of the input values array, or NULL
4373: - values - An array to use for the values, or NULL to have it allocated automatically
4375: Output Parameters:
4376: + csize - The number of values in the closure
4377: - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4379: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4380: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4381: $ assembly function, and a user may already have allocated storage for this operation.
4382: $
4383: $ A typical use could be
4384: $
4385: $ values = NULL;
4386: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4387: $ for (cl = 0; cl < clSize; ++cl) {
4388: $ <Compute on closure>
4389: $ }
4390: $ DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4391: $
4392: $ or
4393: $
4394: $ PetscMalloc1(clMaxSize, &values);
4395: $ for (p = pStart; p < pEnd; ++p) {
4396: $ clSize = clMaxSize;
4397: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4398: $ for (cl = 0; cl < clSize; ++cl) {
4399: $ <Compute on closure>
4400: $ }
4401: $ }
4402: $ PetscFree(values);
4404: Fortran Notes:
4405: Since it returns an array, this routine is only available in Fortran 90, and you must
4406: include petsc.h90 in your code.
4408: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4410: Level: intermediate
4412: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4413: @*/
4414: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4415: {
4416: PetscSection clSection;
4417: IS clPoints;
4418: PetscScalar *array;
4419: const PetscScalar *vArray;
4420: PetscInt *points = NULL;
4421: const PetscInt *clp, *perm;
4422: PetscInt depth, numFields, numPoints, size;
4423: PetscErrorCode ierr;
4427: if (!section) {DMGetLocalSection(dm, §ion);}
4430: DMPlexGetDepth(dm, &depth);
4431: PetscSectionGetNumFields(section, &numFields);
4432: if (depth == 1 && numFields < 2) {
4433: DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4434: return(0);
4435: }
4436: /* Get points */
4437: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4438: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4439: /* Get array */
4440: if (!values || !*values) {
4441: PetscInt asize = 0, dof, p;
4443: for (p = 0; p < numPoints*2; p += 2) {
4444: PetscSectionGetDof(section, points[p], &dof);
4445: asize += dof;
4446: }
4447: if (!values) {
4448: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4449: if (csize) *csize = asize;
4450: return(0);
4451: }
4452: DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4453: } else {
4454: array = *values;
4455: }
4456: VecGetArrayRead(v, &vArray);
4457: /* Get values */
4458: if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4459: else {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4460: /* Cleanup points */
4461: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4462: /* Cleanup array */
4463: VecRestoreArrayRead(v, &vArray);
4464: if (!*values) {
4465: if (csize) *csize = size;
4466: *values = array;
4467: } else {
4468: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4469: *csize = size;
4470: }
4471: return(0);
4472: }
4474: /*@C
4475: DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4477: Not collective
4479: Input Parameters:
4480: + dm - The DM
4481: . section - The section describing the layout in v, or NULL to use the default section
4482: . v - The local vector
4483: . point - The point in the DM
4484: . csize - The number of values in the closure, or NULL
4485: - values - The array of values, which is a borrowed array and should not be freed
4487: Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4489: Fortran Notes:
4490: Since it returns an array, this routine is only available in Fortran 90, and you must
4491: include petsc.h90 in your code.
4493: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4495: Level: intermediate
4497: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4498: @*/
4499: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4500: {
4501: PetscInt size = 0;
4505: /* Should work without recalculating size */
4506: DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4507: *values = NULL;
4508: return(0);
4509: }
4511: PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;}
4512: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;}
4514: PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
4515: {
4516: PetscInt cdof; /* The number of constraints on this point */
4517: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4518: PetscScalar *a;
4519: PetscInt off, cind = 0, k;
4520: PetscErrorCode ierr;
4523: PetscSectionGetConstraintDof(section, point, &cdof);
4524: PetscSectionGetOffset(section, point, &off);
4525: a = &array[off];
4526: if (!cdof || setBC) {
4527: if (clperm) {
4528: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4529: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}}
4530: } else {
4531: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4532: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}}
4533: }
4534: } else {
4535: PetscSectionGetConstraintIndices(section, point, &cdofs);
4536: if (clperm) {
4537: if (perm) {for (k = 0; k < dof; ++k) {
4538: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4539: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4540: }
4541: } else {
4542: for (k = 0; k < dof; ++k) {
4543: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4544: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4545: }
4546: }
4547: } else {
4548: if (perm) {
4549: for (k = 0; k < dof; ++k) {
4550: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4551: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4552: }
4553: } else {
4554: for (k = 0; k < dof; ++k) {
4555: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4556: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4557: }
4558: }
4559: }
4560: }
4561: return(0);
4562: }
4564: PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
4565: {
4566: PetscInt cdof; /* The number of constraints on this point */
4567: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4568: PetscScalar *a;
4569: PetscInt off, cind = 0, k;
4570: PetscErrorCode ierr;
4573: PetscSectionGetConstraintDof(section, point, &cdof);
4574: PetscSectionGetOffset(section, point, &off);
4575: a = &array[off];
4576: if (cdof) {
4577: PetscSectionGetConstraintIndices(section, point, &cdofs);
4578: if (clperm) {
4579: if (perm) {
4580: for (k = 0; k < dof; ++k) {
4581: if ((cind < cdof) && (k == cdofs[cind])) {
4582: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4583: cind++;
4584: }
4585: }
4586: } else {
4587: for (k = 0; k < dof; ++k) {
4588: if ((cind < cdof) && (k == cdofs[cind])) {
4589: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4590: cind++;
4591: }
4592: }
4593: }
4594: } else {
4595: if (perm) {
4596: for (k = 0; k < dof; ++k) {
4597: if ((cind < cdof) && (k == cdofs[cind])) {
4598: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4599: cind++;
4600: }
4601: }
4602: } else {
4603: for (k = 0; k < dof; ++k) {
4604: if ((cind < cdof) && (k == cdofs[cind])) {
4605: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4606: cind++;
4607: }
4608: }
4609: }
4610: }
4611: }
4612: return(0);
4613: }
4615: PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4616: {
4617: PetscScalar *a;
4618: PetscInt fdof, foff, fcdof, foffset = *offset;
4619: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4620: PetscInt cind = 0, b;
4621: PetscErrorCode ierr;
4624: PetscSectionGetFieldDof(section, point, f, &fdof);
4625: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4626: PetscSectionGetFieldOffset(section, point, f, &foff);
4627: a = &array[foff];
4628: if (!fcdof || setBC) {
4629: if (clperm) {
4630: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4631: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}}
4632: } else {
4633: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4634: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}}
4635: }
4636: } else {
4637: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4638: if (clperm) {
4639: if (perm) {
4640: for (b = 0; b < fdof; b++) {
4641: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4642: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4643: }
4644: } else {
4645: for (b = 0; b < fdof; b++) {
4646: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4647: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4648: }
4649: }
4650: } else {
4651: if (perm) {
4652: for (b = 0; b < fdof; b++) {
4653: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4654: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4655: }
4656: } else {
4657: for (b = 0; b < fdof; b++) {
4658: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4659: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4660: }
4661: }
4662: }
4663: }
4664: *offset += fdof;
4665: return(0);
4666: }
4668: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4669: {
4670: PetscScalar *a;
4671: PetscInt fdof, foff, fcdof, foffset = *offset;
4672: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4673: PetscInt cind = 0, ncind = 0, b;
4674: PetscBool ncSet, fcSet;
4675: PetscErrorCode ierr;
4678: PetscSectionGetFieldDof(section, point, f, &fdof);
4679: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4680: PetscSectionGetFieldOffset(section, point, f, &foff);
4681: a = &array[foff];
4682: if (fcdof) {
4683: /* We just override fcdof and fcdofs with Ncc and comps */
4684: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4685: if (clperm) {
4686: if (perm) {
4687: if (comps) {
4688: for (b = 0; b < fdof; b++) {
4689: ncSet = fcSet = PETSC_FALSE;
4690: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4691: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4692: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4693: }
4694: } else {
4695: for (b = 0; b < fdof; b++) {
4696: if ((cind < fcdof) && (b == fcdofs[cind])) {
4697: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4698: ++cind;
4699: }
4700: }
4701: }
4702: } else {
4703: if (comps) {
4704: for (b = 0; b < fdof; b++) {
4705: ncSet = fcSet = PETSC_FALSE;
4706: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4707: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4708: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}
4709: }
4710: } else {
4711: for (b = 0; b < fdof; b++) {
4712: if ((cind < fcdof) && (b == fcdofs[cind])) {
4713: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4714: ++cind;
4715: }
4716: }
4717: }
4718: }
4719: } else {
4720: if (perm) {
4721: if (comps) {
4722: for (b = 0; b < fdof; b++) {
4723: ncSet = fcSet = PETSC_FALSE;
4724: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4725: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4726: if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4727: }
4728: } else {
4729: for (b = 0; b < fdof; b++) {
4730: if ((cind < fcdof) && (b == fcdofs[cind])) {
4731: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4732: ++cind;
4733: }
4734: }
4735: }
4736: } else {
4737: if (comps) {
4738: for (b = 0; b < fdof; b++) {
4739: ncSet = fcSet = PETSC_FALSE;
4740: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4741: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4742: if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}
4743: }
4744: } else {
4745: for (b = 0; b < fdof; b++) {
4746: if ((cind < fcdof) && (b == fcdofs[cind])) {
4747: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4748: ++cind;
4749: }
4750: }
4751: }
4752: }
4753: }
4754: }
4755: *offset += fdof;
4756: return(0);
4757: }
4759: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4760: {
4761: PetscScalar *array;
4762: const PetscInt *cone, *coneO;
4763: PetscInt pStart, pEnd, p, numPoints, off, dof;
4764: PetscErrorCode ierr;
4767: PetscSectionGetChart(section, &pStart, &pEnd);
4768: DMPlexGetConeSize(dm, point, &numPoints);
4769: DMPlexGetCone(dm, point, &cone);
4770: DMPlexGetConeOrientation(dm, point, &coneO);
4771: VecGetArray(v, &array);
4772: for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4773: const PetscInt cp = !p ? point : cone[p-1];
4774: const PetscInt o = !p ? 0 : coneO[p-1];
4776: if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4777: PetscSectionGetDof(section, cp, &dof);
4778: /* ADD_VALUES */
4779: {
4780: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4781: PetscScalar *a;
4782: PetscInt cdof, coff, cind = 0, k;
4784: PetscSectionGetConstraintDof(section, cp, &cdof);
4785: PetscSectionGetOffset(section, cp, &coff);
4786: a = &array[coff];
4787: if (!cdof) {
4788: if (o >= 0) {
4789: for (k = 0; k < dof; ++k) {
4790: a[k] += values[off+k];
4791: }
4792: } else {
4793: for (k = 0; k < dof; ++k) {
4794: a[k] += values[off+dof-k-1];
4795: }
4796: }
4797: } else {
4798: PetscSectionGetConstraintIndices(section, cp, &cdofs);
4799: if (o >= 0) {
4800: for (k = 0; k < dof; ++k) {
4801: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4802: a[k] += values[off+k];
4803: }
4804: } else {
4805: for (k = 0; k < dof; ++k) {
4806: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4807: a[k] += values[off+dof-k-1];
4808: }
4809: }
4810: }
4811: }
4812: }
4813: VecRestoreArray(v, &array);
4814: return(0);
4815: }
4817: /*@C
4818: DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4820: Not collective
4822: Input Parameters:
4823: + dm - The DM
4824: . section - The section describing the layout in v, or NULL to use the default section
4825: . v - The local vector
4826: . point - The point in the DM
4827: . values - The array of values
4828: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4829: where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
4831: Fortran Notes:
4832: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4834: Level: intermediate
4836: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4837: @*/
4838: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4839: {
4840: PetscSection clSection;
4841: IS clPoints;
4842: PetscScalar *array;
4843: PetscInt *points = NULL;
4844: const PetscInt *clp, *clperm;
4845: PetscInt depth, numFields, numPoints, p;
4846: PetscErrorCode ierr;
4850: if (!section) {DMGetLocalSection(dm, §ion);}
4853: DMPlexGetDepth(dm, &depth);
4854: PetscSectionGetNumFields(section, &numFields);
4855: if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4856: DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4857: return(0);
4858: }
4859: /* Get points */
4860: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4861: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4862: /* Get array */
4863: VecGetArray(v, &array);
4864: /* Get values */
4865: if (numFields > 0) {
4866: PetscInt offset = 0, f;
4867: for (f = 0; f < numFields; ++f) {
4868: const PetscInt **perms = NULL;
4869: const PetscScalar **flips = NULL;
4871: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4872: switch (mode) {
4873: case INSERT_VALUES:
4874: for (p = 0; p < numPoints; p++) {
4875: const PetscInt point = points[2*p];
4876: const PetscInt *perm = perms ? perms[p] : NULL;
4877: const PetscScalar *flip = flips ? flips[p] : NULL;
4878: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4879: } break;
4880: case INSERT_ALL_VALUES:
4881: for (p = 0; p < numPoints; p++) {
4882: const PetscInt point = points[2*p];
4883: const PetscInt *perm = perms ? perms[p] : NULL;
4884: const PetscScalar *flip = flips ? flips[p] : NULL;
4885: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4886: } break;
4887: case INSERT_BC_VALUES:
4888: for (p = 0; p < numPoints; p++) {
4889: const PetscInt point = points[2*p];
4890: const PetscInt *perm = perms ? perms[p] : NULL;
4891: const PetscScalar *flip = flips ? flips[p] : NULL;
4892: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4893: } break;
4894: case ADD_VALUES:
4895: for (p = 0; p < numPoints; p++) {
4896: const PetscInt point = points[2*p];
4897: const PetscInt *perm = perms ? perms[p] : NULL;
4898: const PetscScalar *flip = flips ? flips[p] : NULL;
4899: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4900: } break;
4901: case ADD_ALL_VALUES:
4902: for (p = 0; p < numPoints; p++) {
4903: const PetscInt point = points[2*p];
4904: const PetscInt *perm = perms ? perms[p] : NULL;
4905: const PetscScalar *flip = flips ? flips[p] : NULL;
4906: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4907: } break;
4908: case ADD_BC_VALUES:
4909: for (p = 0; p < numPoints; p++) {
4910: const PetscInt point = points[2*p];
4911: const PetscInt *perm = perms ? perms[p] : NULL;
4912: const PetscScalar *flip = flips ? flips[p] : NULL;
4913: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4914: } break;
4915: default:
4916: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4917: }
4918: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4919: }
4920: } else {
4921: PetscInt dof, off;
4922: const PetscInt **perms = NULL;
4923: const PetscScalar **flips = NULL;
4925: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4926: switch (mode) {
4927: case INSERT_VALUES:
4928: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4929: const PetscInt point = points[2*p];
4930: const PetscInt *perm = perms ? perms[p] : NULL;
4931: const PetscScalar *flip = flips ? flips[p] : NULL;
4932: PetscSectionGetDof(section, point, &dof);
4933: updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4934: } break;
4935: case INSERT_ALL_VALUES:
4936: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4937: const PetscInt point = points[2*p];
4938: const PetscInt *perm = perms ? perms[p] : NULL;
4939: const PetscScalar *flip = flips ? flips[p] : NULL;
4940: PetscSectionGetDof(section, point, &dof);
4941: updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array);
4942: } break;
4943: case INSERT_BC_VALUES:
4944: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4945: const PetscInt point = points[2*p];
4946: const PetscInt *perm = perms ? perms[p] : NULL;
4947: const PetscScalar *flip = flips ? flips[p] : NULL;
4948: PetscSectionGetDof(section, point, &dof);
4949: updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array);
4950: } break;
4951: case ADD_VALUES:
4952: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4953: const PetscInt point = points[2*p];
4954: const PetscInt *perm = perms ? perms[p] : NULL;
4955: const PetscScalar *flip = flips ? flips[p] : NULL;
4956: PetscSectionGetDof(section, point, &dof);
4957: updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array);
4958: } break;
4959: case ADD_ALL_VALUES:
4960: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4961: const PetscInt point = points[2*p];
4962: const PetscInt *perm = perms ? perms[p] : NULL;
4963: const PetscScalar *flip = flips ? flips[p] : NULL;
4964: PetscSectionGetDof(section, point, &dof);
4965: updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array);
4966: } break;
4967: case ADD_BC_VALUES:
4968: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4969: const PetscInt point = points[2*p];
4970: const PetscInt *perm = perms ? perms[p] : NULL;
4971: const PetscScalar *flip = flips ? flips[p] : NULL;
4972: PetscSectionGetDof(section, point, &dof);
4973: updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array);
4974: } break;
4975: default:
4976: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4977: }
4978: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4979: }
4980: /* Cleanup points */
4981: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4982: /* Cleanup array */
4983: VecRestoreArray(v, &array);
4984: return(0);
4985: }
4987: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4988: {
4989: PetscSection clSection;
4990: IS clPoints;
4991: PetscScalar *array;
4992: PetscInt *points = NULL;
4993: const PetscInt *clp, *clperm;
4994: PetscInt numFields, numPoints, p;
4995: PetscInt offset = 0, f;
4996: PetscErrorCode ierr;
5000: if (!section) {DMGetLocalSection(dm, §ion);}
5003: PetscSectionGetNumFields(section, &numFields);
5004: /* Get points */
5005: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5006: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5007: /* Get array */
5008: VecGetArray(v, &array);
5009: /* Get values */
5010: for (f = 0; f < numFields; ++f) {
5011: const PetscInt **perms = NULL;
5012: const PetscScalar **flips = NULL;
5014: if (!fieldActive[f]) {
5015: for (p = 0; p < numPoints*2; p += 2) {
5016: PetscInt fdof;
5017: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5018: offset += fdof;
5019: }
5020: continue;
5021: }
5022: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5023: switch (mode) {
5024: case INSERT_VALUES:
5025: for (p = 0; p < numPoints; p++) {
5026: const PetscInt point = points[2*p];
5027: const PetscInt *perm = perms ? perms[p] : NULL;
5028: const PetscScalar *flip = flips ? flips[p] : NULL;
5029: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5030: } break;
5031: case INSERT_ALL_VALUES:
5032: for (p = 0; p < numPoints; p++) {
5033: const PetscInt point = points[2*p];
5034: const PetscInt *perm = perms ? perms[p] : NULL;
5035: const PetscScalar *flip = flips ? flips[p] : NULL;
5036: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5037: } break;
5038: case INSERT_BC_VALUES:
5039: for (p = 0; p < numPoints; p++) {
5040: const PetscInt point = points[2*p];
5041: const PetscInt *perm = perms ? perms[p] : NULL;
5042: const PetscScalar *flip = flips ? flips[p] : NULL;
5043: updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
5044: } break;
5045: case ADD_VALUES:
5046: for (p = 0; p < numPoints; p++) {
5047: const PetscInt point = points[2*p];
5048: const PetscInt *perm = perms ? perms[p] : NULL;
5049: const PetscScalar *flip = flips ? flips[p] : NULL;
5050: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5051: } break;
5052: case ADD_ALL_VALUES:
5053: for (p = 0; p < numPoints; p++) {
5054: const PetscInt point = points[2*p];
5055: const PetscInt *perm = perms ? perms[p] : NULL;
5056: const PetscScalar *flip = flips ? flips[p] : NULL;
5057: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5058: } break;
5059: default:
5060: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5061: }
5062: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5063: }
5064: /* Cleanup points */
5065: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5066: /* Cleanup array */
5067: VecRestoreArray(v, &array);
5068: return(0);
5069: }
5071: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
5072: {
5073: PetscMPIInt rank;
5074: PetscInt i, j;
5078: MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
5079: PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
5080: for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
5081: for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
5082: numCIndices = numCIndices ? numCIndices : numRIndices;
5083: for (i = 0; i < numRIndices; i++) {
5084: PetscViewerASCIIPrintf(viewer, "[%d]", rank);
5085: for (j = 0; j < numCIndices; j++) {
5086: #if defined(PETSC_USE_COMPLEX)
5087: PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
5088: #else
5089: PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
5090: #endif
5091: }
5092: PetscViewerASCIIPrintf(viewer, "\n");
5093: }
5094: return(0);
5095: }
5097: /*
5098: DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
5100: Input Parameters:
5101: + section - The section for this data layout
5102: . point - The point contributing dofs with these indices
5103: . off - The global offset of this point
5104: . loff - The local offset of each field
5105: . setBC - The flag determining whether to include indices of bounsary values
5106: . perm - A permutation of the dofs on this point, or NULL
5107: - indperm - A permutation of the entire indices array, or NULL
5109: Output Parameter:
5110: . indices - Indices for dofs on this point
5112: Level: developer
5114: Note: The indices could be local or global, depending on the value of 'off'.
5115: */
5116: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
5117: {
5118: PetscInt dof; /* The number of unknowns on this point */
5119: PetscInt cdof; /* The number of constraints on this point */
5120: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5121: PetscInt cind = 0, k;
5122: PetscErrorCode ierr;
5125: PetscSectionGetDof(section, point, &dof);
5126: PetscSectionGetConstraintDof(section, point, &cdof);
5127: if (!cdof || setBC) {
5128: for (k = 0; k < dof; ++k) {
5129: const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5130: const PetscInt ind = indperm ? indperm[preind] : preind;
5132: indices[ind] = off + k;
5133: }
5134: } else {
5135: PetscSectionGetConstraintIndices(section, point, &cdofs);
5136: for (k = 0; k < dof; ++k) {
5137: const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5138: const PetscInt ind = indperm ? indperm[preind] : preind;
5140: if ((cind < cdof) && (k == cdofs[cind])) {
5141: /* Insert check for returning constrained indices */
5142: indices[ind] = -(off+k+1);
5143: ++cind;
5144: } else {
5145: indices[ind] = off+k-cind;
5146: }
5147: }
5148: }
5149: *loff += dof;
5150: return(0);
5151: }
5153: /*
5154: This version only believes the point offset from the globalSection
5156: . off - The global offset of this point
5157: */
5158: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5159: {
5160: PetscInt numFields, foff, f;
5164: PetscSectionGetNumFields(section, &numFields);
5165: for (f = 0, foff = 0; f < numFields; ++f) {
5166: PetscInt fdof, cfdof;
5167: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5168: PetscInt cind = 0, b;
5169: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5171: PetscSectionGetFieldDof(section, point, f, &fdof);
5172: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5173: if (!cfdof || setBC) {
5174: for (b = 0; b < fdof; ++b) {
5175: const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5176: const PetscInt ind = indperm ? indperm[preind] : preind;
5178: indices[ind] = off+foff+b;
5179: }
5180: } else {
5181: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5182: for (b = 0; b < fdof; ++b) {
5183: const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5184: const PetscInt ind = indperm ? indperm[preind] : preind;
5186: if ((cind < cfdof) && (b == fcdofs[cind])) {
5187: indices[ind] = -(off+foff+b+1);
5188: ++cind;
5189: } else {
5190: indices[ind] = off+foff+b-cind;
5191: }
5192: }
5193: }
5194: foff += (setBC ? fdof : (fdof - cfdof));
5195: foffs[f] += fdof;
5196: }
5197: return(0);
5198: }
5200: /*
5201: This version believes the globalSection offsets for each field, rather than just the point offset
5203: . foffs - The offset into 'indices' for each field, since it is segregated by field
5204: */
5205: PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5206: {
5207: PetscInt numFields, foff, f;
5211: PetscSectionGetNumFields(section, &numFields);
5212: for (f = 0; f < numFields; ++f) {
5213: PetscInt fdof, cfdof;
5214: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5215: PetscInt cind = 0, b;
5216: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5218: PetscSectionGetFieldDof(section, point, f, &fdof);
5219: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5220: PetscSectionGetFieldOffset(globalSection, point, f, &foff);
5221: if (!cfdof || setBC) {
5222: for (b = 0; b < fdof; ++b) {
5223: const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5224: const PetscInt ind = indperm ? indperm[preind] : preind;
5226: indices[ind] = foff+b;
5227: }
5228: } else {
5229: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5230: for (b = 0; b < fdof; ++b) {
5231: const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5232: const PetscInt ind = indperm ? indperm[preind] : preind;
5234: if ((cind < cfdof) && (b == fcdofs[cind])) {
5235: indices[ind] = -(foff+b+1);
5236: ++cind;
5237: } else {
5238: indices[ind] = foff+b-cind;
5239: }
5240: }
5241: }
5242: foffs[f] += fdof;
5243: }
5244: return(0);
5245: }
5247: PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft)
5248: {
5249: Mat cMat;
5250: PetscSection aSec, cSec;
5251: IS aIS;
5252: PetscInt aStart = -1, aEnd = -1;
5253: const PetscInt *anchors;
5254: PetscInt numFields, f, p, q, newP = 0;
5255: PetscInt newNumPoints = 0, newNumIndices = 0;
5256: PetscInt *newPoints, *indices, *newIndices;
5257: PetscInt maxAnchor, maxDof;
5258: PetscInt newOffsets[32];
5259: PetscInt *pointMatOffsets[32];
5260: PetscInt *newPointOffsets[32];
5261: PetscScalar *pointMat[32];
5262: PetscScalar *newValues=NULL,*tmpValues;
5263: PetscBool anyConstrained = PETSC_FALSE;
5264: PetscErrorCode ierr;
5269: PetscSectionGetNumFields(section, &numFields);
5271: DMPlexGetAnchors(dm,&aSec,&aIS);
5272: /* if there are point-to-point constraints */
5273: if (aSec) {
5274: PetscArrayzero(newOffsets, 32);
5275: ISGetIndices(aIS,&anchors);
5276: PetscSectionGetChart(aSec,&aStart,&aEnd);
5277: /* figure out how many points are going to be in the new element matrix
5278: * (we allow double counting, because it's all just going to be summed
5279: * into the global matrix anyway) */
5280: for (p = 0; p < 2*numPoints; p+=2) {
5281: PetscInt b = points[p];
5282: PetscInt bDof = 0, bSecDof;
5284: PetscSectionGetDof(section,b,&bSecDof);
5285: if (!bSecDof) {
5286: continue;
5287: }
5288: if (b >= aStart && b < aEnd) {
5289: PetscSectionGetDof(aSec,b,&bDof);
5290: }
5291: if (bDof) {
5292: /* this point is constrained */
5293: /* it is going to be replaced by its anchors */
5294: PetscInt bOff, q;
5296: anyConstrained = PETSC_TRUE;
5297: newNumPoints += bDof;
5298: PetscSectionGetOffset(aSec,b,&bOff);
5299: for (q = 0; q < bDof; q++) {
5300: PetscInt a = anchors[bOff + q];
5301: PetscInt aDof;
5303: PetscSectionGetDof(section,a,&aDof);
5304: newNumIndices += aDof;
5305: for (f = 0; f < numFields; ++f) {
5306: PetscInt fDof;
5308: PetscSectionGetFieldDof(section, a, f, &fDof);
5309: newOffsets[f+1] += fDof;
5310: }
5311: }
5312: }
5313: else {
5314: /* this point is not constrained */
5315: newNumPoints++;
5316: newNumIndices += bSecDof;
5317: for (f = 0; f < numFields; ++f) {
5318: PetscInt fDof;
5320: PetscSectionGetFieldDof(section, b, f, &fDof);
5321: newOffsets[f+1] += fDof;
5322: }
5323: }
5324: }
5325: }
5326: if (!anyConstrained) {
5327: if (outNumPoints) *outNumPoints = 0;
5328: if (outNumIndices) *outNumIndices = 0;
5329: if (outPoints) *outPoints = NULL;
5330: if (outValues) *outValues = NULL;
5331: if (aSec) {ISRestoreIndices(aIS,&anchors);}
5332: return(0);
5333: }
5335: if (outNumPoints) *outNumPoints = newNumPoints;
5336: if (outNumIndices) *outNumIndices = newNumIndices;
5338: for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
5340: if (!outPoints && !outValues) {
5341: if (offsets) {
5342: for (f = 0; f <= numFields; f++) {
5343: offsets[f] = newOffsets[f];
5344: }
5345: }
5346: if (aSec) {ISRestoreIndices(aIS,&anchors);}
5347: return(0);
5348: }
5350: if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
5352: DMGetDefaultConstraints(dm, &cSec, &cMat);
5354: /* workspaces */
5355: if (numFields) {
5356: for (f = 0; f < numFields; f++) {
5357: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5358: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5359: }
5360: }
5361: else {
5362: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5363: DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5364: }
5366: /* get workspaces for the point-to-point matrices */
5367: if (numFields) {
5368: PetscInt totalOffset, totalMatOffset;
5370: for (p = 0; p < numPoints; p++) {
5371: PetscInt b = points[2*p];
5372: PetscInt bDof = 0, bSecDof;
5374: PetscSectionGetDof(section,b,&bSecDof);
5375: if (!bSecDof) {
5376: for (f = 0; f < numFields; f++) {
5377: newPointOffsets[f][p + 1] = 0;
5378: pointMatOffsets[f][p + 1] = 0;
5379: }
5380: continue;
5381: }
5382: if (b >= aStart && b < aEnd) {
5383: PetscSectionGetDof(aSec, b, &bDof);
5384: }
5385: if (bDof) {
5386: for (f = 0; f < numFields; f++) {
5387: PetscInt fDof, q, bOff, allFDof = 0;
5389: PetscSectionGetFieldDof(section, b, f, &fDof);
5390: PetscSectionGetOffset(aSec, b, &bOff);
5391: for (q = 0; q < bDof; q++) {
5392: PetscInt a = anchors[bOff + q];
5393: PetscInt aFDof;
5395: PetscSectionGetFieldDof(section, a, f, &aFDof);
5396: allFDof += aFDof;
5397: }
5398: newPointOffsets[f][p+1] = allFDof;
5399: pointMatOffsets[f][p+1] = fDof * allFDof;
5400: }
5401: }
5402: else {
5403: for (f = 0; f < numFields; f++) {
5404: PetscInt fDof;
5406: PetscSectionGetFieldDof(section, b, f, &fDof);
5407: newPointOffsets[f][p+1] = fDof;
5408: pointMatOffsets[f][p+1] = 0;
5409: }
5410: }
5411: }
5412: for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5413: newPointOffsets[f][0] = totalOffset;
5414: pointMatOffsets[f][0] = totalMatOffset;
5415: for (p = 0; p < numPoints; p++) {
5416: newPointOffsets[f][p+1] += newPointOffsets[f][p];
5417: pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5418: }
5419: totalOffset = newPointOffsets[f][numPoints];
5420: totalMatOffset = pointMatOffsets[f][numPoints];
5421: DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5422: }
5423: }
5424: else {
5425: for (p = 0; p < numPoints; p++) {
5426: PetscInt b = points[2*p];
5427: PetscInt bDof = 0, bSecDof;
5429: PetscSectionGetDof(section,b,&bSecDof);
5430: if (!bSecDof) {
5431: newPointOffsets[0][p + 1] = 0;
5432: pointMatOffsets[0][p + 1] = 0;
5433: continue;
5434: }
5435: if (b >= aStart && b < aEnd) {
5436: PetscSectionGetDof(aSec, b, &bDof);
5437: }
5438: if (bDof) {
5439: PetscInt bOff, q, allDof = 0;
5441: PetscSectionGetOffset(aSec, b, &bOff);
5442: for (q = 0; q < bDof; q++) {
5443: PetscInt a = anchors[bOff + q], aDof;
5445: PetscSectionGetDof(section, a, &aDof);
5446: allDof += aDof;
5447: }
5448: newPointOffsets[0][p+1] = allDof;
5449: pointMatOffsets[0][p+1] = bSecDof * allDof;
5450: }
5451: else {
5452: newPointOffsets[0][p+1] = bSecDof;
5453: pointMatOffsets[0][p+1] = 0;
5454: }
5455: }
5456: newPointOffsets[0][0] = 0;
5457: pointMatOffsets[0][0] = 0;
5458: for (p = 0; p < numPoints; p++) {
5459: newPointOffsets[0][p+1] += newPointOffsets[0][p];
5460: pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5461: }
5462: DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5463: }
5465: /* output arrays */
5466: DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5468: /* get the point-to-point matrices; construct newPoints */
5469: PetscSectionGetMaxDof(aSec, &maxAnchor);
5470: PetscSectionGetMaxDof(section, &maxDof);
5471: DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5472: DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5473: if (numFields) {
5474: for (p = 0, newP = 0; p < numPoints; p++) {
5475: PetscInt b = points[2*p];
5476: PetscInt o = points[2*p+1];
5477: PetscInt bDof = 0, bSecDof;
5479: PetscSectionGetDof(section, b, &bSecDof);
5480: if (!bSecDof) {
5481: continue;
5482: }
5483: if (b >= aStart && b < aEnd) {
5484: PetscSectionGetDof(aSec, b, &bDof);
5485: }
5486: if (bDof) {
5487: PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5489: fStart[0] = 0;
5490: fEnd[0] = 0;
5491: for (f = 0; f < numFields; f++) {
5492: PetscInt fDof;
5494: PetscSectionGetFieldDof(cSec, b, f, &fDof);
5495: fStart[f+1] = fStart[f] + fDof;
5496: fEnd[f+1] = fStart[f+1];
5497: }
5498: PetscSectionGetOffset(cSec, b, &bOff);
5499: DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);
5501: fAnchorStart[0] = 0;
5502: fAnchorEnd[0] = 0;
5503: for (f = 0; f < numFields; f++) {
5504: PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5506: fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5507: fAnchorEnd[f+1] = fAnchorStart[f + 1];
5508: }
5509: PetscSectionGetOffset(aSec, b, &bOff);
5510: for (q = 0; q < bDof; q++) {
5511: PetscInt a = anchors[bOff + q], aOff;
5513: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5514: newPoints[2*(newP + q)] = a;
5515: newPoints[2*(newP + q) + 1] = 0;
5516: PetscSectionGetOffset(section, a, &aOff);
5517: DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);
5518: }
5519: newP += bDof;
5521: if (outValues) {
5522: /* get the point-to-point submatrix */
5523: for (f = 0; f < numFields; f++) {
5524: MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5525: }
5526: }
5527: }
5528: else {
5529: newPoints[2 * newP] = b;
5530: newPoints[2 * newP + 1] = o;
5531: newP++;
5532: }
5533: }
5534: } else {
5535: for (p = 0; p < numPoints; p++) {
5536: PetscInt b = points[2*p];
5537: PetscInt o = points[2*p+1];
5538: PetscInt bDof = 0, bSecDof;
5540: PetscSectionGetDof(section, b, &bSecDof);
5541: if (!bSecDof) {
5542: continue;
5543: }
5544: if (b >= aStart && b < aEnd) {
5545: PetscSectionGetDof(aSec, b, &bDof);
5546: }
5547: if (bDof) {
5548: PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5550: PetscSectionGetOffset(cSec, b, &bOff);
5551: DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);
5553: PetscSectionGetOffset (aSec, b, &bOff);
5554: for (q = 0; q < bDof; q++) {
5555: PetscInt a = anchors[bOff + q], aOff;
5557: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5559: newPoints[2*(newP + q)] = a;
5560: newPoints[2*(newP + q) + 1] = 0;
5561: PetscSectionGetOffset(section, a, &aOff);
5562: DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);
5563: }
5564: newP += bDof;
5566: /* get the point-to-point submatrix */
5567: if (outValues) {
5568: MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5569: }
5570: }
5571: else {
5572: newPoints[2 * newP] = b;
5573: newPoints[2 * newP + 1] = o;
5574: newP++;
5575: }
5576: }
5577: }
5579: if (outValues) {
5580: DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5581: PetscArrayzero(tmpValues,newNumIndices*numIndices);
5582: /* multiply constraints on the right */
5583: if (numFields) {
5584: for (f = 0; f < numFields; f++) {
5585: PetscInt oldOff = offsets[f];
5587: for (p = 0; p < numPoints; p++) {
5588: PetscInt cStart = newPointOffsets[f][p];
5589: PetscInt b = points[2 * p];
5590: PetscInt c, r, k;
5591: PetscInt dof;
5593: PetscSectionGetFieldDof(section,b,f,&dof);
5594: if (!dof) {
5595: continue;
5596: }
5597: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5598: PetscInt nCols = newPointOffsets[f][p+1]-cStart;
5599: const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5601: for (r = 0; r < numIndices; r++) {
5602: for (c = 0; c < nCols; c++) {
5603: for (k = 0; k < dof; k++) {
5604: tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5605: }
5606: }
5607: }
5608: }
5609: else {
5610: /* copy this column as is */
5611: for (r = 0; r < numIndices; r++) {
5612: for (c = 0; c < dof; c++) {
5613: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5614: }
5615: }
5616: }
5617: oldOff += dof;
5618: }
5619: }
5620: }
5621: else {
5622: PetscInt oldOff = 0;
5623: for (p = 0; p < numPoints; p++) {
5624: PetscInt cStart = newPointOffsets[0][p];
5625: PetscInt b = points[2 * p];
5626: PetscInt c, r, k;
5627: PetscInt dof;
5629: PetscSectionGetDof(section,b,&dof);
5630: if (!dof) {
5631: continue;
5632: }
5633: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5634: PetscInt nCols = newPointOffsets[0][p+1]-cStart;
5635: const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5637: for (r = 0; r < numIndices; r++) {
5638: for (c = 0; c < nCols; c++) {
5639: for (k = 0; k < dof; k++) {
5640: tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5641: }
5642: }
5643: }
5644: }
5645: else {
5646: /* copy this column as is */
5647: for (r = 0; r < numIndices; r++) {
5648: for (c = 0; c < dof; c++) {
5649: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5650: }
5651: }
5652: }
5653: oldOff += dof;
5654: }
5655: }
5657: if (multiplyLeft) {
5658: DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5659: PetscArrayzero(newValues,newNumIndices*newNumIndices);
5660: /* multiply constraints transpose on the left */
5661: if (numFields) {
5662: for (f = 0; f < numFields; f++) {
5663: PetscInt oldOff = offsets[f];
5665: for (p = 0; p < numPoints; p++) {
5666: PetscInt rStart = newPointOffsets[f][p];
5667: PetscInt b = points[2 * p];
5668: PetscInt c, r, k;
5669: PetscInt dof;
5671: PetscSectionGetFieldDof(section,b,f,&dof);
5672: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5673: PetscInt nRows = newPointOffsets[f][p+1]-rStart;
5674: const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5676: for (r = 0; r < nRows; r++) {
5677: for (c = 0; c < newNumIndices; c++) {
5678: for (k = 0; k < dof; k++) {
5679: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5680: }
5681: }
5682: }
5683: }
5684: else {
5685: /* copy this row as is */
5686: for (r = 0; r < dof; r++) {
5687: for (c = 0; c < newNumIndices; c++) {
5688: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5689: }
5690: }
5691: }
5692: oldOff += dof;
5693: }
5694: }
5695: }
5696: else {
5697: PetscInt oldOff = 0;
5699: for (p = 0; p < numPoints; p++) {
5700: PetscInt rStart = newPointOffsets[0][p];
5701: PetscInt b = points[2 * p];
5702: PetscInt c, r, k;
5703: PetscInt dof;
5705: PetscSectionGetDof(section,b,&dof);
5706: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5707: PetscInt nRows = newPointOffsets[0][p+1]-rStart;
5708: const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5710: for (r = 0; r < nRows; r++) {
5711: for (c = 0; c < newNumIndices; c++) {
5712: for (k = 0; k < dof; k++) {
5713: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5714: }
5715: }
5716: }
5717: }
5718: else {
5719: /* copy this row as is */
5720: for (r = 0; r < dof; r++) {
5721: for (c = 0; c < newNumIndices; c++) {
5722: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5723: }
5724: }
5725: }
5726: oldOff += dof;
5727: }
5728: }
5730: DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5731: }
5732: else {
5733: newValues = tmpValues;
5734: }
5735: }
5737: /* clean up */
5738: DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5739: DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5741: if (numFields) {
5742: for (f = 0; f < numFields; f++) {
5743: DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5744: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5745: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5746: }
5747: }
5748: else {
5749: DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5750: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5751: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5752: }
5753: ISRestoreIndices(aIS,&anchors);
5755: /* output */
5756: if (outPoints) {
5757: *outPoints = newPoints;
5758: }
5759: else {
5760: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5761: }
5762: if (outValues) {
5763: *outValues = newValues;
5764: }
5765: for (f = 0; f <= numFields; f++) {
5766: offsets[f] = newOffsets[f];
5767: }
5768: return(0);
5769: }
5771: /*@C
5772: DMPlexGetClosureIndices - Get the global indices in a vector v for all points in the closure of the given point
5774: Not collective
5776: Input Parameters:
5777: + dm - The DM
5778: . section - The section describing the layout in v, or NULL to use the default section
5779: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5780: - point - The mesh point
5782: Output parameters:
5783: + numIndices - The number of indices
5784: . indices - The indices
5785: - outOffsets - Field offset if not NULL
5787: Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5789: Level: advanced
5791: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5792: @*/
5793: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5794: {
5795: PetscSection clSection;
5796: IS clPoints;
5797: const PetscInt *clp, *clperm;
5798: const PetscInt **perms[32] = {NULL};
5799: PetscInt *points = NULL, *pointsNew;
5800: PetscInt numPoints, numPointsNew;
5801: PetscInt offsets[32];
5802: PetscInt Nf, Nind, NindNew, off, globalOff, f, p;
5803: PetscErrorCode ierr;
5811: PetscSectionGetNumFields(section, &Nf);
5812: if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5813: PetscArrayzero(offsets, 32);
5814: /* Get points in closure */
5815: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5816: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5817: /* Get number of indices and indices per field */
5818: for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5819: PetscInt dof, fdof;
5821: PetscSectionGetDof(section, points[p], &dof);
5822: for (f = 0; f < Nf; ++f) {
5823: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5824: offsets[f+1] += fdof;
5825: }
5826: Nind += dof;
5827: }
5828: for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5829: if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5830: if (!Nf) offsets[1] = Nind;
5831: /* Get dual space symmetries */
5832: for (f = 0; f < PetscMax(1,Nf); f++) {
5833: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5834: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5835: }
5836: /* Correct for hanging node constraints */
5837: {
5838: DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5839: if (numPointsNew) {
5840: for (f = 0; f < PetscMax(1,Nf); f++) {
5841: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5842: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5843: }
5844: for (f = 0; f < PetscMax(1,Nf); f++) {
5845: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5846: else {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5847: }
5848: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5849: numPoints = numPointsNew;
5850: Nind = NindNew;
5851: points = pointsNew;
5852: }
5853: }
5854: /* Calculate indices */
5855: DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5856: if (Nf) {
5857: if (outOffsets) {
5858: PetscInt f;
5860: for (f = 0; f <= Nf; f++) {
5861: outOffsets[f] = offsets[f];
5862: }
5863: }
5864: for (p = 0; p < numPoints; p++) {
5865: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5866: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);
5867: }
5868: } else {
5869: for (p = 0, off = 0; p < numPoints; p++) {
5870: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5872: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5873: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);
5874: }
5875: }
5876: /* Cleanup points */
5877: for (f = 0; f < PetscMax(1,Nf); f++) {
5878: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5879: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5880: }
5881: if (numPointsNew) {
5882: DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5883: } else {
5884: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5885: }
5886: if (numIndices) *numIndices = Nind;
5887: return(0);
5888: }
5890: /*@C
5891: DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5893: Not collective
5895: Input Parameters:
5896: + dm - The DM
5897: . section - The section describing the layout in v, or NULL to use the default section
5898: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5899: . point - The mesh point
5900: . numIndices - The number of indices
5901: . indices - The indices
5902: - outOffsets - Field offset if not NULL
5904: Level: advanced
5906: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5907: @*/
5908: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5909: {
5915: DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5916: return(0);
5917: }
5919: /*@C
5920: DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5922: Not collective
5924: Input Parameters:
5925: + dm - The DM
5926: . section - The section describing the layout in v, or NULL to use the default section
5927: . globalSection - The section describing the layout in v, or NULL to use the default global section
5928: . A - The matrix
5929: . point - The point in the DM
5930: . values - The array of values
5931: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5933: Fortran Notes:
5934: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5936: Level: intermediate
5938: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5939: @*/
5940: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5941: {
5942: DM_Plex *mesh = (DM_Plex*) dm->data;
5943: PetscSection clSection;
5944: IS clPoints;
5945: PetscInt *points = NULL, *newPoints;
5946: const PetscInt *clp, *clperm;
5947: PetscInt *indices;
5948: PetscInt offsets[32];
5949: const PetscInt **perms[32] = {NULL};
5950: const PetscScalar **flips[32] = {NULL};
5951: PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5952: PetscScalar *valCopy = NULL;
5953: PetscScalar *newValues;
5954: PetscErrorCode ierr;
5958: if (!section) {DMGetLocalSection(dm, §ion);}
5960: if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5963: PetscSectionGetNumFields(section, &numFields);
5964: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5965: PetscArrayzero(offsets, 32);
5966: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5967: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5968: for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5969: PetscInt fdof;
5971: PetscSectionGetDof(section, points[p], &dof);
5972: for (f = 0; f < numFields; ++f) {
5973: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5974: offsets[f+1] += fdof;
5975: }
5976: numIndices += dof;
5977: }
5978: for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5980: if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5981: /* Get symmetries */
5982: for (f = 0; f < PetscMax(1,numFields); f++) {
5983: if (numFields) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5984: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5985: if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5986: PetscInt foffset = offsets[f];
5988: for (p = 0; p < numPoints; p++) {
5989: PetscInt point = points[2*p], fdof;
5990: const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5992: if (!numFields) {
5993: PetscSectionGetDof(section,point,&fdof);
5994: } else {
5995: PetscSectionGetFieldDof(section,point,f,&fdof);
5996: }
5997: if (flip) {
5998: PetscInt i, j, k;
6000: if (!valCopy) {
6001: DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6002: for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
6003: values = valCopy;
6004: }
6005: for (i = 0; i < fdof; i++) {
6006: PetscScalar fval = flip[i];
6008: for (k = 0; k < numIndices; k++) {
6009: valCopy[numIndices * (foffset + i) + k] *= fval;
6010: valCopy[numIndices * k + (foffset + i)] *= fval;
6011: }
6012: }
6013: }
6014: foffset += fdof;
6015: }
6016: }
6017: }
6018: DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
6019: if (newNumPoints) {
6020: if (valCopy) {
6021: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6022: }
6023: for (f = 0; f < PetscMax(1,numFields); f++) {
6024: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6025: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6026: }
6027: for (f = 0; f < PetscMax(1,numFields); f++) {
6028: if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
6029: else {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
6030: }
6031: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6032: numPoints = newNumPoints;
6033: numIndices = newNumIndices;
6034: points = newPoints;
6035: values = newValues;
6036: }
6037: DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
6038: if (numFields) {
6039: PetscBool useFieldOffsets;
6041: PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
6042: if (useFieldOffsets) {
6043: for (p = 0; p < numPoints; p++) {
6044: DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices);
6045: }
6046: } else {
6047: for (p = 0; p < numPoints; p++) {
6048: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6049: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);
6050: }
6051: }
6052: } else {
6053: for (p = 0, off = 0; p < numPoints; p++) {
6054: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
6055: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6056: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);
6057: }
6058: }
6059: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
6060: MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6061: if (mesh->printFEM > 1) {
6062: PetscInt i;
6063: PetscPrintf(PETSC_COMM_SELF, " Indices:");
6064: for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
6065: PetscPrintf(PETSC_COMM_SELF, "\n");
6066: }
6067: if (ierr) {
6068: PetscMPIInt rank;
6069: PetscErrorCode ierr2;
6071: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6072: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6073: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
6074: ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
6075:
6076: }
6077: for (f = 0; f < PetscMax(1,numFields); f++) {
6078: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6079: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6080: }
6081: if (newNumPoints) {
6082: DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
6083: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
6084: }
6085: else {
6086: if (valCopy) {
6087: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6088: }
6089: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6090: }
6091: DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
6092: return(0);
6093: }
6095: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6096: {
6097: DM_Plex *mesh = (DM_Plex*) dmf->data;
6098: PetscInt *fpoints = NULL, *ftotpoints = NULL;
6099: PetscInt *cpoints = NULL;
6100: PetscInt *findices, *cindices;
6101: const PetscInt *fclperm, *cclperm;
6102: PetscInt foffsets[32], coffsets[32];
6103: CellRefiner cellRefiner;
6104: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6105: PetscErrorCode ierr;
6110: if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6112: if (!csection) {DMGetLocalSection(dmc, &csection);}
6114: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6116: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6119: PetscSectionGetNumFields(fsection, &numFields);
6120: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6121: PetscArrayzero(foffsets, 32);
6122: PetscArrayzero(coffsets, 32);
6123: PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6124: PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6125: /* Column indices */
6126: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6127: maxFPoints = numCPoints;
6128: /* Compress out points not in the section */
6129: /* TODO: Squeeze out points with 0 dof as well */
6130: PetscSectionGetChart(csection, &pStart, &pEnd);
6131: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6132: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6133: cpoints[q*2] = cpoints[p];
6134: cpoints[q*2+1] = cpoints[p+1];
6135: ++q;
6136: }
6137: }
6138: numCPoints = q;
6139: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6140: PetscInt fdof;
6142: PetscSectionGetDof(csection, cpoints[p], &dof);
6143: if (!dof) continue;
6144: for (f = 0; f < numFields; ++f) {
6145: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6146: coffsets[f+1] += fdof;
6147: }
6148: numCIndices += dof;
6149: }
6150: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6151: /* Row indices */
6152: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6153: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6154: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6155: for (r = 0, q = 0; r < numSubcells; ++r) {
6156: /* TODO Map from coarse to fine cells */
6157: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6158: /* Compress out points not in the section */
6159: PetscSectionGetChart(fsection, &pStart, &pEnd);
6160: for (p = 0; p < numFPoints*2; p += 2) {
6161: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6162: PetscSectionGetDof(fsection, fpoints[p], &dof);
6163: if (!dof) continue;
6164: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6165: if (s < q) continue;
6166: ftotpoints[q*2] = fpoints[p];
6167: ftotpoints[q*2+1] = fpoints[p+1];
6168: ++q;
6169: }
6170: }
6171: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6172: }
6173: numFPoints = q;
6174: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6175: PetscInt fdof;
6177: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6178: if (!dof) continue;
6179: for (f = 0; f < numFields; ++f) {
6180: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6181: foffsets[f+1] += fdof;
6182: }
6183: numFIndices += dof;
6184: }
6185: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6187: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6188: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6189: DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6190: DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6191: if (numFields) {
6192: const PetscInt **permsF[32] = {NULL};
6193: const PetscInt **permsC[32] = {NULL};
6195: for (f = 0; f < numFields; f++) {
6196: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6197: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6198: }
6199: for (p = 0; p < numFPoints; p++) {
6200: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6201: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6202: }
6203: for (p = 0; p < numCPoints; p++) {
6204: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6205: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6206: }
6207: for (f = 0; f < numFields; f++) {
6208: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6209: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6210: }
6211: } else {
6212: const PetscInt **permsF = NULL;
6213: const PetscInt **permsC = NULL;
6215: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6216: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6217: for (p = 0, off = 0; p < numFPoints; p++) {
6218: const PetscInt *perm = permsF ? permsF[p] : NULL;
6220: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6221: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6222: }
6223: for (p = 0, off = 0; p < numCPoints; p++) {
6224: const PetscInt *perm = permsC ? permsC[p] : NULL;
6226: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6227: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6228: }
6229: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6230: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6231: }
6232: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
6233: /* TODO: flips */
6234: MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6235: if (ierr) {
6236: PetscMPIInt rank;
6237: PetscErrorCode ierr2;
6239: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6240: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6241: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6242: ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6243: ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6244:
6245: }
6246: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6247: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6248: DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6249: DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6250: return(0);
6251: }
6253: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6254: {
6255: PetscInt *fpoints = NULL, *ftotpoints = NULL;
6256: PetscInt *cpoints = NULL;
6257: PetscInt foffsets[32], coffsets[32];
6258: const PetscInt *fclperm, *cclperm;
6259: CellRefiner cellRefiner;
6260: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6266: if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6268: if (!csection) {DMGetLocalSection(dmc, &csection);}
6270: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6272: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6274: PetscSectionGetNumFields(fsection, &numFields);
6275: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6276: PetscArrayzero(foffsets, 32);
6277: PetscArrayzero(coffsets, 32);
6278: PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6279: PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6280: /* Column indices */
6281: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6282: maxFPoints = numCPoints;
6283: /* Compress out points not in the section */
6284: /* TODO: Squeeze out points with 0 dof as well */
6285: PetscSectionGetChart(csection, &pStart, &pEnd);
6286: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6287: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6288: cpoints[q*2] = cpoints[p];
6289: cpoints[q*2+1] = cpoints[p+1];
6290: ++q;
6291: }
6292: }
6293: numCPoints = q;
6294: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6295: PetscInt fdof;
6297: PetscSectionGetDof(csection, cpoints[p], &dof);
6298: if (!dof) continue;
6299: for (f = 0; f < numFields; ++f) {
6300: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6301: coffsets[f+1] += fdof;
6302: }
6303: numCIndices += dof;
6304: }
6305: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6306: /* Row indices */
6307: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6308: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6309: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6310: for (r = 0, q = 0; r < numSubcells; ++r) {
6311: /* TODO Map from coarse to fine cells */
6312: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6313: /* Compress out points not in the section */
6314: PetscSectionGetChart(fsection, &pStart, &pEnd);
6315: for (p = 0; p < numFPoints*2; p += 2) {
6316: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6317: PetscSectionGetDof(fsection, fpoints[p], &dof);
6318: if (!dof) continue;
6319: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6320: if (s < q) continue;
6321: ftotpoints[q*2] = fpoints[p];
6322: ftotpoints[q*2+1] = fpoints[p+1];
6323: ++q;
6324: }
6325: }
6326: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6327: }
6328: numFPoints = q;
6329: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6330: PetscInt fdof;
6332: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6333: if (!dof) continue;
6334: for (f = 0; f < numFields; ++f) {
6335: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6336: foffsets[f+1] += fdof;
6337: }
6338: numFIndices += dof;
6339: }
6340: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6342: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6343: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6344: if (numFields) {
6345: const PetscInt **permsF[32] = {NULL};
6346: const PetscInt **permsC[32] = {NULL};
6348: for (f = 0; f < numFields; f++) {
6349: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6350: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6351: }
6352: for (p = 0; p < numFPoints; p++) {
6353: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6354: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6355: }
6356: for (p = 0; p < numCPoints; p++) {
6357: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6358: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6359: }
6360: for (f = 0; f < numFields; f++) {
6361: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6362: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6363: }
6364: } else {
6365: const PetscInt **permsF = NULL;
6366: const PetscInt **permsC = NULL;
6368: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6369: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6370: for (p = 0, off = 0; p < numFPoints; p++) {
6371: const PetscInt *perm = permsF ? permsF[p] : NULL;
6373: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6374: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6375: }
6376: for (p = 0, off = 0; p < numCPoints; p++) {
6377: const PetscInt *perm = permsC ? permsC[p] : NULL;
6379: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6380: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6381: }
6382: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6383: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6384: }
6385: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6386: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6387: return(0);
6388: }
6390: /*@
6391: DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6393: Input Parameter:
6394: . dm - The DMPlex object
6396: Output Parameters:
6397: + cMax - The first hybrid cell
6398: . fMax - The first hybrid face
6399: . eMax - The first hybrid edge
6400: - vMax - The first hybrid vertex
6402: Level: developer
6404: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6405: @*/
6406: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6407: {
6408: DM_Plex *mesh = (DM_Plex*) dm->data;
6409: PetscInt dim;
6414: DMGetDimension(dm, &dim);
6415: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6416: if (cMax) *cMax = mesh->hybridPointMax[dim];
6417: if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6418: if (eMax) *eMax = mesh->hybridPointMax[1];
6419: if (vMax) *vMax = mesh->hybridPointMax[0];
6420: return(0);
6421: }
6423: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6424: {
6425: IS is, his;
6426: PetscInt first = 0, stride;
6427: PetscBool isStride;
6431: DMLabelGetStratumIS(depthLabel, d, &is);
6432: PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6433: if (isStride) {
6434: ISStrideGetInfo(is, &first, &stride);
6435: }
6436: if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6437: ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6438: DMLabelSetStratumIS(dimLabel, d, his);
6439: ISDestroy(&his);
6440: ISDestroy(&is);
6441: return(0);
6442: }
6444: /*@
6445: DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6447: Input Parameters:
6448: + dm - The DMPlex object
6449: . cMax - The first hybrid cell
6450: . fMax - The first hybrid face
6451: . eMax - The first hybrid edge
6452: - vMax - The first hybrid vertex
6454: Level: developer
6456: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6457: @*/
6458: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6459: {
6460: DM_Plex *mesh = (DM_Plex*) dm->data;
6461: PetscInt dim;
6466: DMGetDimension(dm, &dim);
6467: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6468: if (cMax >= 0) mesh->hybridPointMax[dim] = cMax;
6469: if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6470: if (eMax >= 0) mesh->hybridPointMax[1] = eMax;
6471: if (vMax >= 0) mesh->hybridPointMax[0] = vMax;
6472: return(0);
6473: }
6475: /*@C
6476: DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6478: Input Parameter:
6479: . dm - The DMPlex object
6481: Output Parameter:
6482: . cellHeight - The height of a cell
6484: Level: developer
6486: .seealso DMPlexSetVTKCellHeight()
6487: @*/
6488: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6489: {
6490: DM_Plex *mesh = (DM_Plex*) dm->data;
6495: *cellHeight = mesh->vtkCellHeight;
6496: return(0);
6497: }
6499: /*@C
6500: DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6502: Input Parameters:
6503: + dm - The DMPlex object
6504: - cellHeight - The height of a cell
6506: Level: developer
6508: .seealso DMPlexGetVTKCellHeight()
6509: @*/
6510: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6511: {
6512: DM_Plex *mesh = (DM_Plex*) dm->data;
6516: mesh->vtkCellHeight = cellHeight;
6517: return(0);
6518: }
6520: /* We can easily have a form that takes an IS instead */
6521: PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6522: {
6523: PetscSection section, globalSection;
6524: PetscInt *numbers, p;
6528: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
6529: PetscSectionSetChart(section, pStart, pEnd);
6530: for (p = pStart; p < pEnd; ++p) {
6531: PetscSectionSetDof(section, p, 1);
6532: }
6533: PetscSectionSetUp(section);
6534: PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6535: PetscMalloc1(pEnd - pStart, &numbers);
6536: for (p = pStart; p < pEnd; ++p) {
6537: PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6538: if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6539: else numbers[p-pStart] += shift;
6540: }
6541: ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6542: if (globalSize) {
6543: PetscLayout layout;
6544: PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6545: PetscLayoutGetSize(layout, globalSize);
6546: PetscLayoutDestroy(&layout);
6547: }
6548: PetscSectionDestroy(§ion);
6549: PetscSectionDestroy(&globalSection);
6550: return(0);
6551: }
6553: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6554: {
6555: PetscInt cellHeight, cStart, cEnd, cMax;
6559: DMPlexGetVTKCellHeight(dm, &cellHeight);
6560: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6561: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6562: if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6563: DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6564: return(0);
6565: }
6567: /*@
6568: DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6570: Input Parameter:
6571: . dm - The DMPlex object
6573: Output Parameter:
6574: . globalCellNumbers - Global cell numbers for all cells on this process
6576: Level: developer
6578: .seealso DMPlexGetVertexNumbering()
6579: @*/
6580: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6581: {
6582: DM_Plex *mesh = (DM_Plex*) dm->data;
6587: if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6588: *globalCellNumbers = mesh->globalCellNumbers;
6589: return(0);
6590: }
6592: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6593: {
6594: PetscInt vStart, vEnd, vMax;
6599: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6600: DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6601: if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6602: DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6603: return(0);
6604: }
6606: /*@
6607: DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
6609: Input Parameter:
6610: . dm - The DMPlex object
6612: Output Parameter:
6613: . globalVertexNumbers - Global vertex numbers for all vertices on this process
6615: Level: developer
6617: .seealso DMPlexGetCellNumbering()
6618: @*/
6619: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6620: {
6621: DM_Plex *mesh = (DM_Plex*) dm->data;
6626: if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6627: *globalVertexNumbers = mesh->globalVertexNumbers;
6628: return(0);
6629: }
6631: /*@
6632: DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6634: Input Parameter:
6635: . dm - The DMPlex object
6637: Output Parameter:
6638: . globalPointNumbers - Global numbers for all points on this process
6640: Level: developer
6642: .seealso DMPlexGetCellNumbering()
6643: @*/
6644: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6645: {
6646: IS nums[4];
6647: PetscInt depths[4], gdepths[4], starts[4];
6648: PetscInt depth, d, shift = 0;
6653: DMPlexGetDepth(dm, &depth);
6654: /* For unstratified meshes use dim instead of depth */
6655: if (depth < 0) {DMGetDimension(dm, &depth);}
6656: for (d = 0; d <= depth; ++d) {
6657: PetscInt end;
6659: depths[d] = depth-d;
6660: DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6661: if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6662: }
6663: PetscSortIntWithArray(depth+1, starts, depths);
6664: MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6665: for (d = 0; d <= depth; ++d) {
6666: if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6667: }
6668: for (d = 0; d <= depth; ++d) {
6669: PetscInt pStart, pEnd, gsize;
6671: DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6672: DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6673: shift += gsize;
6674: }
6675: ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6676: for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6677: return(0);
6678: }
6681: /*@
6682: DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6684: Input Parameter:
6685: . dm - The DMPlex object
6687: Output Parameter:
6688: . ranks - The rank field
6690: Options Database Keys:
6691: . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6693: Level: intermediate
6695: .seealso: DMView()
6696: @*/
6697: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6698: {
6699: DM rdm;
6700: PetscFE fe;
6701: PetscScalar *r;
6702: PetscMPIInt rank;
6703: PetscInt dim, cStart, cEnd, c;
6709: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6710: DMClone(dm, &rdm);
6711: DMGetDimension(rdm, &dim);
6712: PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6713: PetscObjectSetName((PetscObject) fe, "rank");
6714: DMSetField(rdm, 0, NULL, (PetscObject) fe);
6715: PetscFEDestroy(&fe);
6716: DMCreateDS(rdm);
6717: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6718: DMCreateGlobalVector(rdm, ranks);
6719: PetscObjectSetName((PetscObject) *ranks, "partition");
6720: VecGetArray(*ranks, &r);
6721: for (c = cStart; c < cEnd; ++c) {
6722: PetscScalar *lr;
6724: DMPlexPointGlobalRef(rdm, c, r, &lr);
6725: *lr = rank;
6726: }
6727: VecRestoreArray(*ranks, &r);
6728: DMDestroy(&rdm);
6729: return(0);
6730: }
6732: /*@
6733: DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
6735: Input Parameters:
6736: + dm - The DMPlex
6737: - label - The DMLabel
6739: Output Parameter:
6740: . val - The label value field
6742: Options Database Keys:
6743: . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
6745: Level: intermediate
6747: .seealso: DMView()
6748: @*/
6749: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6750: {
6751: DM rdm;
6752: PetscFE fe;
6753: PetscScalar *v;
6754: PetscInt dim, cStart, cEnd, c;
6761: DMClone(dm, &rdm);
6762: DMGetDimension(rdm, &dim);
6763: PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6764: PetscObjectSetName((PetscObject) fe, "label_value");
6765: DMSetField(rdm, 0, NULL, (PetscObject) fe);
6766: PetscFEDestroy(&fe);
6767: DMCreateDS(rdm);
6768: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6769: DMCreateGlobalVector(rdm, val);
6770: PetscObjectSetName((PetscObject) *val, "label_value");
6771: VecGetArray(*val, &v);
6772: for (c = cStart; c < cEnd; ++c) {
6773: PetscScalar *lv;
6774: PetscInt cval;
6776: DMPlexPointGlobalRef(rdm, c, v, &lv);
6777: DMLabelGetValue(label, c, &cval);
6778: *lv = cval;
6779: }
6780: VecRestoreArray(*val, &v);
6781: DMDestroy(&rdm);
6782: return(0);
6783: }
6785: /*@
6786: DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6788: Input Parameter:
6789: . dm - The DMPlex object
6791: Note: This is a useful diagnostic when creating meshes programmatically.
6793: Level: developer
6795: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6796: @*/
6797: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6798: {
6799: PetscSection coneSection, supportSection;
6800: const PetscInt *cone, *support;
6801: PetscInt coneSize, c, supportSize, s;
6802: PetscInt pStart, pEnd, p, pp, csize, ssize;
6803: PetscBool storagecheck = PETSC_TRUE;
6804: PetscErrorCode ierr;
6808: DMPlexGetConeSection(dm, &coneSection);
6809: DMPlexGetSupportSection(dm, &supportSection);
6810: /* Check that point p is found in the support of its cone points, and vice versa */
6811: DMPlexGetChart(dm, &pStart, &pEnd);
6812: for (p = pStart; p < pEnd; ++p) {
6813: DMPlexGetConeSize(dm, p, &coneSize);
6814: DMPlexGetCone(dm, p, &cone);
6815: for (c = 0; c < coneSize; ++c) {
6816: PetscBool dup = PETSC_FALSE;
6817: PetscInt d;
6818: for (d = c-1; d >= 0; --d) {
6819: if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6820: }
6821: DMPlexGetSupportSize(dm, cone[c], &supportSize);
6822: DMPlexGetSupport(dm, cone[c], &support);
6823: for (s = 0; s < supportSize; ++s) {
6824: if (support[s] == p) break;
6825: }
6826: if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6827: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6828: for (s = 0; s < coneSize; ++s) {
6829: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6830: }
6831: PetscPrintf(PETSC_COMM_SELF, "\n");
6832: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6833: for (s = 0; s < supportSize; ++s) {
6834: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6835: }
6836: PetscPrintf(PETSC_COMM_SELF, "\n");
6837: if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6838: else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6839: }
6840: }
6841: DMPlexGetTreeParent(dm, p, &pp, NULL);
6842: if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6843: DMPlexGetSupportSize(dm, p, &supportSize);
6844: DMPlexGetSupport(dm, p, &support);
6845: for (s = 0; s < supportSize; ++s) {
6846: DMPlexGetConeSize(dm, support[s], &coneSize);
6847: DMPlexGetCone(dm, support[s], &cone);
6848: for (c = 0; c < coneSize; ++c) {
6849: DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
6850: if (cone[c] != pp) { c = 0; break; }
6851: if (cone[c] == p) break;
6852: }
6853: if (c >= coneSize) {
6854: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6855: for (c = 0; c < supportSize; ++c) {
6856: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6857: }
6858: PetscPrintf(PETSC_COMM_SELF, "\n");
6859: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6860: for (c = 0; c < coneSize; ++c) {
6861: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6862: }
6863: PetscPrintf(PETSC_COMM_SELF, "\n");
6864: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6865: }
6866: }
6867: }
6868: if (storagecheck) {
6869: PetscSectionGetStorageSize(coneSection, &csize);
6870: PetscSectionGetStorageSize(supportSection, &ssize);
6871: if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6872: }
6873: return(0);
6874: }
6876: /*@
6877: DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6879: Input Parameters:
6880: + dm - The DMPlex object
6881: - cellHeight - Normally 0
6883: Note: This is a useful diagnostic when creating meshes programmatically.
6884: Currently applicable only to homogeneous simplex or tensor meshes.
6886: Level: developer
6888: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6889: @*/
6890: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
6891: {
6892: PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6893: PetscBool isSimplex = PETSC_FALSE;
6898: DMGetDimension(dm, &dim);
6899: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6900: if (cStart < cEnd) {
6901: DMPlexGetConeSize(dm, cStart, &c);
6902: isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE;
6903: }
6904: switch (dim) {
6905: case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6906: case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6907: case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6908: default:
6909: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6910: }
6911: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6912: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6913: cMax = cMax >= 0 ? cMax : cEnd;
6914: for (c = cStart; c < cMax; ++c) {
6915: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6917: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6918: for (cl = 0; cl < closureSize*2; cl += 2) {
6919: const PetscInt p = closure[cl];
6920: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6921: }
6922: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6923: if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D", c, coneSize, numCorners);
6924: }
6925: for (c = cMax; c < cEnd; ++c) {
6926: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6928: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6929: for (cl = 0; cl < closureSize*2; cl += 2) {
6930: const PetscInt p = closure[cl];
6931: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6932: }
6933: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6934: if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has %D vertices > %D", c, coneSize, numHybridCorners);
6935: }
6936: return(0);
6937: }
6939: /*@
6940: DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6942: Input Parameters:
6943: + dm - The DMPlex object
6944: - cellHeight - Normally 0
6946: Note: This is a useful diagnostic when creating meshes programmatically.
6948: Level: developer
6950: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6951: @*/
6952: PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
6953: {
6954: PetscInt pMax[4];
6955: PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h;
6960: DMGetDimension(dm, &dim);
6961: DMPlexGetDepth(dm, &depth);
6962: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6963: DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6964: for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
6965: DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6966: for (c = cStart; c < cEnd; ++c) {
6967: const PetscInt *cone, *ornt, *faces;
6968: PetscInt numFaces, faceSize, coneSize,f;
6969: PetscInt *closure = NULL, closureSize, cl, numCorners = 0;
6971: if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6972: DMPlexGetConeSize(dm, c, &coneSize);
6973: DMPlexGetCone(dm, c, &cone);
6974: DMPlexGetConeOrientation(dm, c, &ornt);
6975: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6976: for (cl = 0; cl < closureSize*2; cl += 2) {
6977: const PetscInt p = closure[cl];
6978: if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6979: }
6980: DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6981: if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6982: for (f = 0; f < numFaces; ++f) {
6983: PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6985: DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6986: for (cl = 0; cl < fclosureSize*2; cl += 2) {
6987: const PetscInt p = fclosure[cl];
6988: if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6989: }
6990: 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);
6991: for (v = 0; v < fnumCorners; ++v) {
6992: 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]);
6993: }
6994: DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6995: }
6996: DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6997: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6998: }
6999: }
7000: return(0);
7001: }
7003: /*@
7004: DMPlexCheckGeometry - Check the geometry of mesh cells
7006: Input Parameter:
7007: . dm - The DMPlex object
7009: Note: This is a useful diagnostic when creating meshes programmatically.
7011: Level: developer
7013: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
7014: @*/
7015: PetscErrorCode DMPlexCheckGeometry(DM dm)
7016: {
7017: PetscReal detJ, J[9], refVol = 1.0;
7018: PetscReal vol;
7019: PetscInt dim, depth, d, cStart, cEnd, c, cMax;
7023: DMGetDimension(dm, &dim);
7024: DMPlexGetDepth(dm, &depth);
7025: for (d = 0; d < dim; ++d) refVol *= 2.0;
7026: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7027: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
7028: cMax = cMax < 0 ? cEnd : cMax;
7029: for (c = cStart; c < cMax; ++c) {
7030: DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
7031: if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
7032: PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
7033: if (depth > 1) {
7034: DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
7035: if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
7036: PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
7037: }
7038: }
7039: return(0);
7040: }
7042: static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
7043: {
7044: PetscInt i,l,n;
7045: const PetscInt *cone;
7049: *missingPoint = -1;
7050: DMPlexGetConeSize(dm, p, &n);
7051: DMPlexGetCone(dm, p, &cone);
7052: for (i=0; i<n; i++) {
7053: PetscFindInt(cone[i], npoints, points, &l);
7054: if (l < 0) {
7055: *missingPoint = cone[i];
7056: break;
7057: }
7058: }
7059: return(0);
7060: }
7062: /*@
7063: DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
7065: Input Parameters:
7066: . dm - The DMPlex object
7068: Notes:
7069: This is mainly intended for debugging/testing purposes.
7070: It currently checks only meshes with no partition overlapping.
7072: Level: developer
7074: .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
7075: @*/
7076: PetscErrorCode DMPlexCheckPointSF(DM dm)
7077: {
7078: PetscSF sf;
7079: PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
7080: const PetscInt *locals;
7081: PetscErrorCode ierr;
7085: DMPlexGetDepth(dm, &depth);
7086: DMGetPointSF(dm, &sf);
7087: DMPlexGetOverlap(dm, &d);
7088: if (d) {
7089: PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");
7090: return(0);
7091: }
7092: PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);
7094: /* 1) check there are no faces in 2D, cells in 3D, in interface */
7095: DMPlexGetVTKCellHeight(dm, &d);
7096: DMPlexGetHeightStratum(dm, d, &plo, &phi);
7097: for (i=0; i<nleaves; i++) {
7098: p = locals[i];
7099: if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
7100: }
7102: /* 2) if some point is in interface, then all its cone points must be also in interface */
7103: for (i=0; i<nleaves; i++) {
7104: p = locals[i];
7105: DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);
7106: if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
7107: }
7108: return(0);
7109: }
7111: typedef struct cell_stats
7112: {
7113: PetscReal min, max, sum, squaresum;
7114: PetscInt count;
7115: } cell_stats_t;
7117: static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
7118: {
7119: PetscInt i, N = *len;
7121: for (i = 0; i < N; i++) {
7122: cell_stats_t *A = (cell_stats_t *) a;
7123: cell_stats_t *B = (cell_stats_t *) b;
7125: B->min = PetscMin(A->min,B->min);
7126: B->max = PetscMax(A->max,B->max);
7127: B->sum += A->sum;
7128: B->squaresum += A->squaresum;
7129: B->count += A->count;
7130: }
7131: }
7133: /*@
7134: DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
7136: Collective on dm
7138: Input Parameters:
7139: + dm - The DMPlex object
7140: . output - If true, statistics will be displayed on stdout
7141: - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
7143: Note: This is mainly intended for debugging/testing purposes.
7145: Level: developer
7147: .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
7148: @*/
7149: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
7150: {
7151: DM dmCoarse;
7152: cell_stats_t stats, globalStats;
7153: MPI_Comm comm = PetscObjectComm((PetscObject)dm);
7154: PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
7155: PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
7156: PetscInt cdim, cStart, cEnd, cMax, c, eStart, eEnd, count = 0;
7157: PetscMPIInt rank,size;
7162: stats.min = PETSC_MAX_REAL;
7163: stats.max = PETSC_MIN_REAL;
7164: stats.sum = stats.squaresum = 0.;
7165: stats.count = 0;
7167: MPI_Comm_size(comm, &size);
7168: MPI_Comm_rank(comm, &rank);
7169: DMGetCoordinateDim(dm,&cdim);
7170: PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);
7171: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
7172: DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);
7173: DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
7174: cMax = cMax < 0 ? cEnd : cMax;
7175: for (c = cStart; c < cMax; c++) {
7176: PetscInt i;
7177: PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
7179: DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
7180: if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
7181: for (i = 0; i < PetscSqr(cdim); ++i) {
7182: frobJ += J[i] * J[i];
7183: frobInvJ += invJ[i] * invJ[i];
7184: }
7185: cond2 = frobJ * frobInvJ;
7186: cond = PetscSqrtReal(cond2);
7188: stats.min = PetscMin(stats.min,cond);
7189: stats.max = PetscMax(stats.max,cond);
7190: stats.sum += cond;
7191: stats.squaresum += cond2;
7192: stats.count++;
7193: if (output && cond > limit) {
7194: PetscSection coordSection;
7195: Vec coordsLocal;
7196: PetscScalar *coords = NULL;
7197: PetscInt Nv, d, clSize, cl, *closure = NULL;
7199: DMGetCoordinatesLocal(dm, &coordsLocal);
7200: DMGetCoordinateSection(dm, &coordSection);
7201: DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7202: PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);
7203: for (i = 0; i < Nv/cdim; ++i) {
7204: PetscSynchronizedPrintf(comm, " Vertex %D: (", i);
7205: for (d = 0; d < cdim; ++d) {
7206: if (d > 0) {PetscSynchronizedPrintf(comm, ", ");}
7207: PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));
7208: }
7209: PetscSynchronizedPrintf(comm, ")\n");
7210: }
7211: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7212: for (cl = 0; cl < clSize*2; cl += 2) {
7213: const PetscInt edge = closure[cl];
7215: if ((edge >= eStart) && (edge < eEnd)) {
7216: PetscReal len;
7218: DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);
7219: PetscSynchronizedPrintf(comm, " Edge %D: length %g\n", edge, (double) len);
7220: }
7221: }
7222: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7223: DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7224: }
7225: }
7226: if (output) {PetscSynchronizedFlush(comm, NULL);}
7228: if (size > 1) {
7229: PetscMPIInt blockLengths[2] = {4,1};
7230: MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
7231: MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType;
7232: MPI_Op statReduce;
7234: MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
7235: MPI_Type_commit(&statType);
7236: MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
7237: MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
7238: MPI_Op_free(&statReduce);
7239: MPI_Type_free(&statType);
7240: } else {
7241: PetscArraycpy(&globalStats,&stats,1);
7242: }
7243: if (!rank) {
7244: count = globalStats.count;
7245: min = globalStats.min;
7246: max = globalStats.max;
7247: mean = globalStats.sum / globalStats.count;
7248: stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
7249: }
7251: if (output) {
7252: PetscPrintf(comm,"Mesh with %D cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double) min, (double) max, (double) mean, (double) stdev);
7253: }
7254: PetscFree2(J,invJ);
7256: DMGetCoarseDM(dm,&dmCoarse);
7257: if (dmCoarse) {
7258: PetscBool isplex;
7260: PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
7261: if (isplex) {
7262: DMPlexCheckCellShape(dmCoarse,output,condLimit);
7263: }
7264: }
7265: return(0);
7266: }
7268: /* Pointwise interpolation
7269: Just code FEM for now
7270: u^f = I u^c
7271: sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
7272: u^f_i = sum_j psi^f_i I phi^c_j u^c_j
7273: I_{ij} = psi^f_i phi^c_j
7274: */
7275: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
7276: {
7277: PetscSection gsc, gsf;
7278: PetscInt m, n;
7279: void *ctx;
7280: DM cdm;
7281: PetscBool regular, ismatis;
7285: DMGetGlobalSection(dmFine, &gsf);
7286: PetscSectionGetConstrainedStorageSize(gsf, &m);
7287: DMGetGlobalSection(dmCoarse, &gsc);
7288: PetscSectionGetConstrainedStorageSize(gsc, &n);
7290: PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
7291: MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
7292: MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7293: MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
7294: DMGetApplicationContext(dmFine, &ctx);
7296: DMGetCoarseDM(dmFine, &cdm);
7297: DMPlexGetRegularRefinement(dmFine, ®ular);
7298: if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
7299: else {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
7300: MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
7301: if (scaling) {
7302: /* Use naive scaling */
7303: DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
7304: }
7305: return(0);
7306: }
7308: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
7309: {
7311: VecScatter ctx;
7314: DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
7315: MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
7316: VecScatterDestroy(&ctx);
7317: return(0);
7318: }
7320: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
7321: {
7322: PetscSection gsc, gsf;
7323: PetscInt m, n;
7324: void *ctx;
7325: DM cdm;
7326: PetscBool regular;
7330: DMGetGlobalSection(dmFine, &gsf);
7331: PetscSectionGetConstrainedStorageSize(gsf, &m);
7332: DMGetGlobalSection(dmCoarse, &gsc);
7333: PetscSectionGetConstrainedStorageSize(gsc, &n);
7335: MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
7336: MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7337: MatSetType(*mass, dmCoarse->mattype);
7338: DMGetApplicationContext(dmFine, &ctx);
7340: DMGetCoarseDM(dmFine, &cdm);
7341: DMPlexGetRegularRefinement(dmFine, ®ular);
7342: if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
7343: else {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
7344: MatViewFromOptions(*mass, NULL, "-mass_mat_view");
7345: return(0);
7346: }
7348: /*@
7349: DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7351: Input Parameter:
7352: . dm - The DMPlex object
7354: Output Parameter:
7355: . regular - The flag
7357: Level: intermediate
7359: .seealso: DMPlexSetRegularRefinement()
7360: @*/
7361: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7362: {
7366: *regular = ((DM_Plex *) dm->data)->regularRefinement;
7367: return(0);
7368: }
7370: /*@
7371: DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7373: Input Parameters:
7374: + dm - The DMPlex object
7375: - regular - The flag
7377: Level: intermediate
7379: .seealso: DMPlexGetRegularRefinement()
7380: @*/
7381: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7382: {
7385: ((DM_Plex *) dm->data)->regularRefinement = regular;
7386: return(0);
7387: }
7389: /* anchors */
7390: /*@
7391: DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to
7392: call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
7394: not collective
7396: Input Parameters:
7397: . dm - The DMPlex object
7399: Output Parameters:
7400: + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
7401: - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
7404: Level: intermediate
7406: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7407: @*/
7408: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7409: {
7410: DM_Plex *plex = (DM_Plex *)dm->data;
7415: if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7416: if (anchorSection) *anchorSection = plex->anchorSection;
7417: if (anchorIS) *anchorIS = plex->anchorIS;
7418: return(0);
7419: }
7421: /*@
7422: DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions,
7423: when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
7424: point's degrees of freedom to be a linear combination of other points' degrees of freedom.
7426: After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
7427: DMGetConstraints() and filling in the entries in the constraint matrix.
7429: collective on dm
7431: Input Parameters:
7432: + dm - The DMPlex object
7433: . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. Must have a local communicator (PETSC_COMM_SELF or derivative).
7434: - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative).
7436: The reference counts of anchorSection and anchorIS are incremented.
7438: Level: intermediate
7440: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7441: @*/
7442: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7443: {
7444: DM_Plex *plex = (DM_Plex *)dm->data;
7445: PetscMPIInt result;
7450: if (anchorSection) {
7452: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7453: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7454: }
7455: if (anchorIS) {
7457: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7458: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7459: }
7461: PetscObjectReference((PetscObject)anchorSection);
7462: PetscSectionDestroy(&plex->anchorSection);
7463: plex->anchorSection = anchorSection;
7465: PetscObjectReference((PetscObject)anchorIS);
7466: ISDestroy(&plex->anchorIS);
7467: plex->anchorIS = anchorIS;
7469: #if defined(PETSC_USE_DEBUG)
7470: if (anchorIS && anchorSection) {
7471: PetscInt size, a, pStart, pEnd;
7472: const PetscInt *anchors;
7474: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7475: ISGetLocalSize(anchorIS,&size);
7476: ISGetIndices(anchorIS,&anchors);
7477: for (a = 0; a < size; a++) {
7478: PetscInt p;
7480: p = anchors[a];
7481: if (p >= pStart && p < pEnd) {
7482: PetscInt dof;
7484: PetscSectionGetDof(anchorSection,p,&dof);
7485: if (dof) {
7486: PetscErrorCode ierr2;
7488: ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7489: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7490: }
7491: }
7492: }
7493: ISRestoreIndices(anchorIS,&anchors);
7494: }
7495: #endif
7496: /* reset the generic constraints */
7497: DMSetDefaultConstraints(dm,NULL,NULL);
7498: return(0);
7499: }
7501: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7502: {
7503: PetscSection anchorSection;
7504: PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
7509: DMPlexGetAnchors(dm,&anchorSection,NULL);
7510: PetscSectionCreate(PETSC_COMM_SELF,cSec);
7511: PetscSectionGetNumFields(section,&numFields);
7512: if (numFields) {
7513: PetscInt f;
7514: PetscSectionSetNumFields(*cSec,numFields);
7516: for (f = 0; f < numFields; f++) {
7517: PetscInt numComp;
7519: PetscSectionGetFieldComponents(section,f,&numComp);
7520: PetscSectionSetFieldComponents(*cSec,f,numComp);
7521: }
7522: }
7523: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7524: PetscSectionGetChart(section,&sStart,&sEnd);
7525: pStart = PetscMax(pStart,sStart);
7526: pEnd = PetscMin(pEnd,sEnd);
7527: pEnd = PetscMax(pStart,pEnd);
7528: PetscSectionSetChart(*cSec,pStart,pEnd);
7529: for (p = pStart; p < pEnd; p++) {
7530: PetscSectionGetDof(anchorSection,p,&dof);
7531: if (dof) {
7532: PetscSectionGetDof(section,p,&dof);
7533: PetscSectionSetDof(*cSec,p,dof);
7534: for (f = 0; f < numFields; f++) {
7535: PetscSectionGetFieldDof(section,p,f,&dof);
7536: PetscSectionSetFieldDof(*cSec,p,f,dof);
7537: }
7538: }
7539: }
7540: PetscSectionSetUp(*cSec);
7541: return(0);
7542: }
7544: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7545: {
7546: PetscSection aSec;
7547: PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7548: const PetscInt *anchors;
7549: PetscInt numFields, f;
7550: IS aIS;
7555: PetscSectionGetStorageSize(cSec, &m);
7556: PetscSectionGetStorageSize(section, &n);
7557: MatCreate(PETSC_COMM_SELF,cMat);
7558: MatSetSizes(*cMat,m,n,m,n);
7559: MatSetType(*cMat,MATSEQAIJ);
7560: DMPlexGetAnchors(dm,&aSec,&aIS);
7561: ISGetIndices(aIS,&anchors);
7562: /* cSec will be a subset of aSec and section */
7563: PetscSectionGetChart(cSec,&pStart,&pEnd);
7564: PetscMalloc1(m+1,&i);
7565: i[0] = 0;
7566: PetscSectionGetNumFields(section,&numFields);
7567: for (p = pStart; p < pEnd; p++) {
7568: PetscInt rDof, rOff, r;
7570: PetscSectionGetDof(aSec,p,&rDof);
7571: if (!rDof) continue;
7572: PetscSectionGetOffset(aSec,p,&rOff);
7573: if (numFields) {
7574: for (f = 0; f < numFields; f++) {
7575: annz = 0;
7576: for (r = 0; r < rDof; r++) {
7577: a = anchors[rOff + r];
7578: PetscSectionGetFieldDof(section,a,f,&aDof);
7579: annz += aDof;
7580: }
7581: PetscSectionGetFieldDof(cSec,p,f,&dof);
7582: PetscSectionGetFieldOffset(cSec,p,f,&off);
7583: for (q = 0; q < dof; q++) {
7584: i[off + q + 1] = i[off + q] + annz;
7585: }
7586: }
7587: }
7588: else {
7589: annz = 0;
7590: for (q = 0; q < dof; q++) {
7591: a = anchors[off + q];
7592: PetscSectionGetDof(section,a,&aDof);
7593: annz += aDof;
7594: }
7595: PetscSectionGetDof(cSec,p,&dof);
7596: PetscSectionGetOffset(cSec,p,&off);
7597: for (q = 0; q < dof; q++) {
7598: i[off + q + 1] = i[off + q] + annz;
7599: }
7600: }
7601: }
7602: nnz = i[m];
7603: PetscMalloc1(nnz,&j);
7604: offset = 0;
7605: for (p = pStart; p < pEnd; p++) {
7606: if (numFields) {
7607: for (f = 0; f < numFields; f++) {
7608: PetscSectionGetFieldDof(cSec,p,f,&dof);
7609: for (q = 0; q < dof; q++) {
7610: PetscInt rDof, rOff, r;
7611: PetscSectionGetDof(aSec,p,&rDof);
7612: PetscSectionGetOffset(aSec,p,&rOff);
7613: for (r = 0; r < rDof; r++) {
7614: PetscInt s;
7616: a = anchors[rOff + r];
7617: PetscSectionGetFieldDof(section,a,f,&aDof);
7618: PetscSectionGetFieldOffset(section,a,f,&aOff);
7619: for (s = 0; s < aDof; s++) {
7620: j[offset++] = aOff + s;
7621: }
7622: }
7623: }
7624: }
7625: }
7626: else {
7627: PetscSectionGetDof(cSec,p,&dof);
7628: for (q = 0; q < dof; q++) {
7629: PetscInt rDof, rOff, r;
7630: PetscSectionGetDof(aSec,p,&rDof);
7631: PetscSectionGetOffset(aSec,p,&rOff);
7632: for (r = 0; r < rDof; r++) {
7633: PetscInt s;
7635: a = anchors[rOff + r];
7636: PetscSectionGetDof(section,a,&aDof);
7637: PetscSectionGetOffset(section,a,&aOff);
7638: for (s = 0; s < aDof; s++) {
7639: j[offset++] = aOff + s;
7640: }
7641: }
7642: }
7643: }
7644: }
7645: MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7646: PetscFree(i);
7647: PetscFree(j);
7648: ISRestoreIndices(aIS,&anchors);
7649: return(0);
7650: }
7652: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7653: {
7654: DM_Plex *plex = (DM_Plex *)dm->data;
7655: PetscSection anchorSection, section, cSec;
7656: Mat cMat;
7661: DMPlexGetAnchors(dm,&anchorSection,NULL);
7662: if (anchorSection) {
7663: PetscInt Nf;
7665: DMGetLocalSection(dm,§ion);
7666: DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7667: DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7668: DMGetNumFields(dm,&Nf);
7669: if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7670: DMSetDefaultConstraints(dm,cSec,cMat);
7671: PetscSectionDestroy(&cSec);
7672: MatDestroy(&cMat);
7673: }
7674: return(0);
7675: }
7677: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7678: {
7679: IS subis;
7680: PetscSection section, subsection;
7684: DMGetLocalSection(dm, §ion);
7685: if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7686: if (!subdm) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7687: /* Create subdomain */
7688: DMPlexFilter(dm, label, value, subdm);
7689: /* Create submodel */
7690: DMPlexCreateSubpointIS(*subdm, &subis);
7691: PetscSectionCreateSubmeshSection(section, subis, &subsection);
7692: ISDestroy(&subis);
7693: DMSetLocalSection(*subdm, subsection);
7694: PetscSectionDestroy(&subsection);
7695: DMCopyDisc(dm, *subdm);
7696: /* Create map from submodel to global model */
7697: if (is) {
7698: PetscSection sectionGlobal, subsectionGlobal;
7699: IS spIS;
7700: const PetscInt *spmap;
7701: PetscInt *subIndices;
7702: PetscInt subSize = 0, subOff = 0, pStart, pEnd, p;
7703: PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
7705: DMPlexCreateSubpointIS(*subdm, &spIS);
7706: ISGetIndices(spIS, &spmap);
7707: PetscSectionGetNumFields(section, &Nf);
7708: DMGetGlobalSection(dm, §ionGlobal);
7709: DMGetGlobalSection(*subdm, &subsectionGlobal);
7710: PetscSectionGetChart(subsection, &pStart, &pEnd);
7711: for (p = pStart; p < pEnd; ++p) {
7712: PetscInt gdof, pSubSize = 0;
7714: PetscSectionGetDof(sectionGlobal, p, &gdof);
7715: if (gdof > 0) {
7716: for (f = 0; f < Nf; ++f) {
7717: PetscInt fdof, fcdof;
7719: PetscSectionGetFieldDof(subsection, p, f, &fdof);
7720: PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7721: pSubSize += fdof-fcdof;
7722: }
7723: subSize += pSubSize;
7724: if (pSubSize) {
7725: if (bs < 0) {
7726: bs = pSubSize;
7727: } else if (bs != pSubSize) {
7728: /* Layout does not admit a pointwise block size */
7729: bs = 1;
7730: }
7731: }
7732: }
7733: }
7734: /* Must have same blocksize on all procs (some might have no points) */
7735: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7736: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7737: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7738: else {bs = bsMinMax[0];}
7739: PetscMalloc1(subSize, &subIndices);
7740: for (p = pStart; p < pEnd; ++p) {
7741: PetscInt gdof, goff;
7743: PetscSectionGetDof(subsectionGlobal, p, &gdof);
7744: if (gdof > 0) {
7745: const PetscInt point = spmap[p];
7747: PetscSectionGetOffset(sectionGlobal, point, &goff);
7748: for (f = 0; f < Nf; ++f) {
7749: PetscInt fdof, fcdof, fc, f2, poff = 0;
7751: /* Can get rid of this loop by storing field information in the global section */
7752: for (f2 = 0; f2 < f; ++f2) {
7753: PetscSectionGetFieldDof(section, p, f2, &fdof);
7754: PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7755: poff += fdof-fcdof;
7756: }
7757: PetscSectionGetFieldDof(section, p, f, &fdof);
7758: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7759: for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7760: subIndices[subOff] = goff+poff+fc;
7761: }
7762: }
7763: }
7764: }
7765: ISRestoreIndices(spIS, &spmap);
7766: ISDestroy(&spIS);
7767: ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7768: if (bs > 1) {
7769: /* We need to check that the block size does not come from non-contiguous fields */
7770: PetscInt i, j, set = 1;
7771: for (i = 0; i < subSize; i += bs) {
7772: for (j = 0; j < bs; ++j) {
7773: if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7774: }
7775: }
7776: if (set) {ISSetBlockSize(*is, bs);}
7777: }
7778: /* Attach nullspace */
7779: for (f = 0; f < Nf; ++f) {
7780: (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7781: if ((*subdm)->nullspaceConstructors[f]) break;
7782: }
7783: if (f < Nf) {
7784: MatNullSpace nullSpace;
7786: (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7787: PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7788: MatNullSpaceDestroy(&nullSpace);
7789: }
7790: }
7791: return(0);
7792: }