Actual source code: plex.c
petsc-3.12.5 2020-03-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 depth in the DAG of each point. For cell-vertex
2815: meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
2816: until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2817: manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed
2818: via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1.
2820: The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
2821: if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
2822: we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose
2823: to interpolate only that one (e0), so that
2824: $ cone(c0) = {e0, v2}
2825: $ cone(e0) = {v0, v1}
2826: If DMPlexStratify() is run on this mesh, it will give depths
2827: $ depth 0 = {v0, v1, v2}
2828: $ depth 1 = {e0, c0}
2829: where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
2831: DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
2833: Level: beginner
2835: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2836: @*/
2837: PetscErrorCode DMPlexStratify(DM dm)
2838: {
2839: DM_Plex *mesh = (DM_Plex*) dm->data;
2840: DMLabel label;
2841: PetscInt pStart, pEnd, p;
2842: PetscInt numRoots = 0, numLeaves = 0;
2843: PetscInt cMax, fMax, eMax, vMax;
2848: PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2850: /* Create depth label */
2851: DMPlexGetChart(dm, &pStart, &pEnd);
2852: DMCreateLabel(dm, "depth");
2853: DMPlexGetDepthLabel(dm, &label);
2855: {
2856: /* Initialize roots and count leaves */
2857: PetscInt sMin = PETSC_MAX_INT;
2858: PetscInt sMax = PETSC_MIN_INT;
2859: PetscInt coneSize, supportSize;
2861: for (p = pStart; p < pEnd; ++p) {
2862: DMPlexGetConeSize(dm, p, &coneSize);
2863: DMPlexGetSupportSize(dm, p, &supportSize);
2864: if (!coneSize && supportSize) {
2865: sMin = PetscMin(p, sMin);
2866: sMax = PetscMax(p, sMax);
2867: ++numRoots;
2868: } else if (!supportSize && coneSize) {
2869: ++numLeaves;
2870: } else if (!supportSize && !coneSize) {
2871: /* Isolated points */
2872: sMin = PetscMin(p, sMin);
2873: sMax = PetscMax(p, sMax);
2874: }
2875: }
2876: DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);
2877: }
2879: if (numRoots + numLeaves == (pEnd - pStart)) {
2880: PetscInt sMin = PETSC_MAX_INT;
2881: PetscInt sMax = PETSC_MIN_INT;
2882: PetscInt coneSize, supportSize;
2884: for (p = pStart; p < pEnd; ++p) {
2885: DMPlexGetConeSize(dm, p, &coneSize);
2886: DMPlexGetSupportSize(dm, p, &supportSize);
2887: if (!supportSize && coneSize) {
2888: sMin = PetscMin(p, sMin);
2889: sMax = PetscMax(p, sMax);
2890: }
2891: }
2892: DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);
2893: } else {
2894: PetscInt level = 0;
2895: PetscInt qStart, qEnd, q;
2897: DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2898: while (qEnd > qStart) {
2899: PetscInt sMin = PETSC_MAX_INT;
2900: PetscInt sMax = PETSC_MIN_INT;
2902: for (q = qStart; q < qEnd; ++q) {
2903: const PetscInt *support;
2904: PetscInt supportSize, s;
2906: DMPlexGetSupportSize(dm, q, &supportSize);
2907: DMPlexGetSupport(dm, q, &support);
2908: for (s = 0; s < supportSize; ++s) {
2909: sMin = PetscMin(support[s], sMin);
2910: sMax = PetscMax(support[s], sMax);
2911: }
2912: }
2913: DMLabelGetNumValues(label, &level);
2914: DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);
2915: DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2916: }
2917: }
2918: { /* just in case there is an empty process */
2919: PetscInt numValues, maxValues = 0, v;
2921: DMLabelGetNumValues(label, &numValues);
2922: MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2923: for (v = numValues; v < maxValues; v++) {
2924: DMLabelAddStratum(label, v);
2925: }
2926: }
2927: PetscObjectStateGet((PetscObject) label, &mesh->depthState);
2929: DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2930: if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2931: PetscInt dim;
2932: DMLabel dimLabel;
2934: DMGetDimension(dm, &dim);
2935: DMCreateLabel(dm, "dim");
2936: DMGetLabel(dm, "dim", &dimLabel);
2937: if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2938: if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2939: if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2940: if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2941: }
2942: PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2943: return(0);
2944: }
2946: /*@C
2947: DMPlexGetJoin - Get an array for the join of the set of points
2949: Not Collective
2951: Input Parameters:
2952: + dm - The DMPlex object
2953: . numPoints - The number of input points for the join
2954: - points - The input points
2956: Output Parameters:
2957: + numCoveredPoints - The number of points in the join
2958: - coveredPoints - The points in the join
2960: Level: intermediate
2962: Note: Currently, this is restricted to a single level join
2964: Fortran Notes:
2965: Since it returns an array, this routine is only available in Fortran 90, and you must
2966: include petsc.h90 in your code.
2968: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2970: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2971: @*/
2972: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2973: {
2974: DM_Plex *mesh = (DM_Plex*) dm->data;
2975: PetscInt *join[2];
2976: PetscInt joinSize, i = 0;
2977: PetscInt dof, off, p, c, m;
2985: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2986: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2987: /* Copy in support of first point */
2988: PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2989: PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2990: for (joinSize = 0; joinSize < dof; ++joinSize) {
2991: join[i][joinSize] = mesh->supports[off+joinSize];
2992: }
2993: /* Check each successive support */
2994: for (p = 1; p < numPoints; ++p) {
2995: PetscInt newJoinSize = 0;
2997: PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2998: PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2999: for (c = 0; c < dof; ++c) {
3000: const PetscInt point = mesh->supports[off+c];
3002: for (m = 0; m < joinSize; ++m) {
3003: if (point == join[i][m]) {
3004: join[1-i][newJoinSize++] = point;
3005: break;
3006: }
3007: }
3008: }
3009: joinSize = newJoinSize;
3010: i = 1-i;
3011: }
3012: *numCoveredPoints = joinSize;
3013: *coveredPoints = join[i];
3014: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3015: return(0);
3016: }
3018: /*@C
3019: DMPlexRestoreJoin - Restore an array for the join of the set of points
3021: Not Collective
3023: Input Parameters:
3024: + dm - The DMPlex object
3025: . numPoints - The number of input points for the join
3026: - points - The input points
3028: Output Parameters:
3029: + numCoveredPoints - The number of points in the join
3030: - coveredPoints - The points in the join
3032: Fortran Notes:
3033: Since it returns an array, this routine is only available in Fortran 90, and you must
3034: include petsc.h90 in your code.
3036: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3038: Level: intermediate
3040: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
3041: @*/
3042: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3043: {
3051: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3052: if (numCoveredPoints) *numCoveredPoints = 0;
3053: return(0);
3054: }
3056: /*@C
3057: DMPlexGetFullJoin - Get an array for the join of the set of points
3059: Not Collective
3061: Input Parameters:
3062: + dm - The DMPlex object
3063: . numPoints - The number of input points for the join
3064: - points - The input points
3066: Output Parameters:
3067: + numCoveredPoints - The number of points in the join
3068: - coveredPoints - The points in the join
3070: Fortran Notes:
3071: Since it returns an array, this routine is only available in Fortran 90, and you must
3072: include petsc.h90 in your code.
3074: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3076: Level: intermediate
3078: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
3079: @*/
3080: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3081: {
3082: DM_Plex *mesh = (DM_Plex*) dm->data;
3083: PetscInt *offsets, **closures;
3084: PetscInt *join[2];
3085: PetscInt depth = 0, maxSize, joinSize = 0, i = 0;
3086: PetscInt p, d, c, m, ms;
3095: DMPlexGetDepth(dm, &depth);
3096: PetscCalloc1(numPoints, &closures);
3097: DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3098: ms = mesh->maxSupportSize;
3099: maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
3100: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
3101: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);
3103: for (p = 0; p < numPoints; ++p) {
3104: PetscInt closureSize;
3106: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);
3108: offsets[p*(depth+2)+0] = 0;
3109: for (d = 0; d < depth+1; ++d) {
3110: PetscInt pStart, pEnd, i;
3112: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
3113: for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
3114: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3115: offsets[p*(depth+2)+d+1] = i;
3116: break;
3117: }
3118: }
3119: if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
3120: }
3121: 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);
3122: }
3123: for (d = 0; d < depth+1; ++d) {
3124: PetscInt dof;
3126: /* Copy in support of first point */
3127: dof = offsets[d+1] - offsets[d];
3128: for (joinSize = 0; joinSize < dof; ++joinSize) {
3129: join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
3130: }
3131: /* Check each successive cone */
3132: for (p = 1; p < numPoints && joinSize; ++p) {
3133: PetscInt newJoinSize = 0;
3135: dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
3136: for (c = 0; c < dof; ++c) {
3137: const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
3139: for (m = 0; m < joinSize; ++m) {
3140: if (point == join[i][m]) {
3141: join[1-i][newJoinSize++] = point;
3142: break;
3143: }
3144: }
3145: }
3146: joinSize = newJoinSize;
3147: i = 1-i;
3148: }
3149: if (joinSize) break;
3150: }
3151: *numCoveredPoints = joinSize;
3152: *coveredPoints = join[i];
3153: for (p = 0; p < numPoints; ++p) {
3154: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
3155: }
3156: PetscFree(closures);
3157: DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3158: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3159: return(0);
3160: }
3162: /*@C
3163: DMPlexGetMeet - Get an array for the meet of the set of points
3165: Not Collective
3167: Input Parameters:
3168: + dm - The DMPlex object
3169: . numPoints - The number of input points for the meet
3170: - points - The input points
3172: Output Parameters:
3173: + numCoveredPoints - The number of points in the meet
3174: - coveredPoints - The points in the meet
3176: Level: intermediate
3178: Note: Currently, this is restricted to a single level meet
3180: Fortran Notes:
3181: Since it returns an array, this routine is only available in Fortran 90, and you must
3182: include petsc.h90 in your code.
3184: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3186: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
3187: @*/
3188: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
3189: {
3190: DM_Plex *mesh = (DM_Plex*) dm->data;
3191: PetscInt *meet[2];
3192: PetscInt meetSize, i = 0;
3193: PetscInt dof, off, p, c, m;
3201: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
3202: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
3203: /* Copy in cone of first point */
3204: PetscSectionGetDof(mesh->coneSection, points[0], &dof);
3205: PetscSectionGetOffset(mesh->coneSection, points[0], &off);
3206: for (meetSize = 0; meetSize < dof; ++meetSize) {
3207: meet[i][meetSize] = mesh->cones[off+meetSize];
3208: }
3209: /* Check each successive cone */
3210: for (p = 1; p < numPoints; ++p) {
3211: PetscInt newMeetSize = 0;
3213: PetscSectionGetDof(mesh->coneSection, points[p], &dof);
3214: PetscSectionGetOffset(mesh->coneSection, points[p], &off);
3215: for (c = 0; c < dof; ++c) {
3216: const PetscInt point = mesh->cones[off+c];
3218: for (m = 0; m < meetSize; ++m) {
3219: if (point == meet[i][m]) {
3220: meet[1-i][newMeetSize++] = point;
3221: break;
3222: }
3223: }
3224: }
3225: meetSize = newMeetSize;
3226: i = 1-i;
3227: }
3228: *numCoveringPoints = meetSize;
3229: *coveringPoints = meet[i];
3230: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3231: return(0);
3232: }
3234: /*@C
3235: DMPlexRestoreMeet - Restore an array for the meet of the set of points
3237: Not Collective
3239: Input Parameters:
3240: + dm - The DMPlex object
3241: . numPoints - The number of input points for the meet
3242: - points - The input points
3244: Output Parameters:
3245: + numCoveredPoints - The number of points in the meet
3246: - coveredPoints - The points in the meet
3248: Level: intermediate
3250: Fortran Notes:
3251: Since it returns an array, this routine is only available in Fortran 90, and you must
3252: include petsc.h90 in your code.
3254: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3256: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
3257: @*/
3258: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3259: {
3267: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3268: if (numCoveredPoints) *numCoveredPoints = 0;
3269: return(0);
3270: }
3272: /*@C
3273: DMPlexGetFullMeet - Get an array for the meet of the set of points
3275: Not Collective
3277: Input Parameters:
3278: + dm - The DMPlex object
3279: . numPoints - The number of input points for the meet
3280: - points - The input points
3282: Output Parameters:
3283: + numCoveredPoints - The number of points in the meet
3284: - coveredPoints - The points in the meet
3286: Level: intermediate
3288: Fortran Notes:
3289: Since it returns an array, this routine is only available in Fortran 90, and you must
3290: include petsc.h90 in your code.
3292: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3294: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3295: @*/
3296: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3297: {
3298: DM_Plex *mesh = (DM_Plex*) dm->data;
3299: PetscInt *offsets, **closures;
3300: PetscInt *meet[2];
3301: PetscInt height = 0, maxSize, meetSize = 0, i = 0;
3302: PetscInt p, h, c, m, mc;
3311: DMPlexGetDepth(dm, &height);
3312: PetscMalloc1(numPoints, &closures);
3313: DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3314: mc = mesh->maxConeSize;
3315: maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3316: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3317: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);
3319: for (p = 0; p < numPoints; ++p) {
3320: PetscInt closureSize;
3322: DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);
3324: offsets[p*(height+2)+0] = 0;
3325: for (h = 0; h < height+1; ++h) {
3326: PetscInt pStart, pEnd, i;
3328: DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3329: for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3330: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3331: offsets[p*(height+2)+h+1] = i;
3332: break;
3333: }
3334: }
3335: if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3336: }
3337: 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);
3338: }
3339: for (h = 0; h < height+1; ++h) {
3340: PetscInt dof;
3342: /* Copy in cone of first point */
3343: dof = offsets[h+1] - offsets[h];
3344: for (meetSize = 0; meetSize < dof; ++meetSize) {
3345: meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3346: }
3347: /* Check each successive cone */
3348: for (p = 1; p < numPoints && meetSize; ++p) {
3349: PetscInt newMeetSize = 0;
3351: dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
3352: for (c = 0; c < dof; ++c) {
3353: const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
3355: for (m = 0; m < meetSize; ++m) {
3356: if (point == meet[i][m]) {
3357: meet[1-i][newMeetSize++] = point;
3358: break;
3359: }
3360: }
3361: }
3362: meetSize = newMeetSize;
3363: i = 1-i;
3364: }
3365: if (meetSize) break;
3366: }
3367: *numCoveredPoints = meetSize;
3368: *coveredPoints = meet[i];
3369: for (p = 0; p < numPoints; ++p) {
3370: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3371: }
3372: PetscFree(closures);
3373: DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3374: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3375: return(0);
3376: }
3378: /*@C
3379: DMPlexEqual - Determine if two DMs have the same topology
3381: Not Collective
3383: Input Parameters:
3384: + dmA - A DMPlex object
3385: - dmB - A DMPlex object
3387: Output Parameters:
3388: . equal - PETSC_TRUE if the topologies are identical
3390: Level: intermediate
3392: Notes:
3393: We are not solving graph isomorphism, so we do not permutation.
3395: .seealso: DMPlexGetCone()
3396: @*/
3397: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3398: {
3399: PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
3407: *equal = PETSC_FALSE;
3408: DMPlexGetDepth(dmA, &depth);
3409: DMPlexGetDepth(dmB, &depthB);
3410: if (depth != depthB) return(0);
3411: DMPlexGetChart(dmA, &pStart, &pEnd);
3412: DMPlexGetChart(dmB, &pStartB, &pEndB);
3413: if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3414: for (p = pStart; p < pEnd; ++p) {
3415: const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3416: PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s;
3418: DMPlexGetConeSize(dmA, p, &coneSize);
3419: DMPlexGetCone(dmA, p, &cone);
3420: DMPlexGetConeOrientation(dmA, p, &ornt);
3421: DMPlexGetConeSize(dmB, p, &coneSizeB);
3422: DMPlexGetCone(dmB, p, &coneB);
3423: DMPlexGetConeOrientation(dmB, p, &orntB);
3424: if (coneSize != coneSizeB) return(0);
3425: for (c = 0; c < coneSize; ++c) {
3426: if (cone[c] != coneB[c]) return(0);
3427: if (ornt[c] != orntB[c]) return(0);
3428: }
3429: DMPlexGetSupportSize(dmA, p, &supportSize);
3430: DMPlexGetSupport(dmA, p, &support);
3431: DMPlexGetSupportSize(dmB, p, &supportSizeB);
3432: DMPlexGetSupport(dmB, p, &supportB);
3433: if (supportSize != supportSizeB) return(0);
3434: for (s = 0; s < supportSize; ++s) {
3435: if (support[s] != supportB[s]) return(0);
3436: }
3437: }
3438: *equal = PETSC_TRUE;
3439: return(0);
3440: }
3442: /*@C
3443: DMPlexGetNumFaceVertices - Returns the number of vertices on a face
3445: Not Collective
3447: Input Parameters:
3448: + dm - The DMPlex
3449: . cellDim - The cell dimension
3450: - numCorners - The number of vertices on a cell
3452: Output Parameters:
3453: . numFaceVertices - The number of vertices on a face
3455: Level: developer
3457: Notes:
3458: Of course this can only work for a restricted set of symmetric shapes
3460: .seealso: DMPlexGetCone()
3461: @*/
3462: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3463: {
3464: MPI_Comm comm;
3468: PetscObjectGetComm((PetscObject)dm,&comm);
3470: switch (cellDim) {
3471: case 0:
3472: *numFaceVertices = 0;
3473: break;
3474: case 1:
3475: *numFaceVertices = 1;
3476: break;
3477: case 2:
3478: switch (numCorners) {
3479: case 3: /* triangle */
3480: *numFaceVertices = 2; /* Edge has 2 vertices */
3481: break;
3482: case 4: /* quadrilateral */
3483: *numFaceVertices = 2; /* Edge has 2 vertices */
3484: break;
3485: case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3486: *numFaceVertices = 3; /* Edge has 3 vertices */
3487: break;
3488: case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3489: *numFaceVertices = 3; /* Edge has 3 vertices */
3490: break;
3491: default:
3492: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3493: }
3494: break;
3495: case 3:
3496: switch (numCorners) {
3497: case 4: /* tetradehdron */
3498: *numFaceVertices = 3; /* Face has 3 vertices */
3499: break;
3500: case 6: /* tet cohesive cells */
3501: *numFaceVertices = 4; /* Face has 4 vertices */
3502: break;
3503: case 8: /* hexahedron */
3504: *numFaceVertices = 4; /* Face has 4 vertices */
3505: break;
3506: case 9: /* tet cohesive Lagrange cells */
3507: *numFaceVertices = 6; /* Face has 6 vertices */
3508: break;
3509: case 10: /* quadratic tetrahedron */
3510: *numFaceVertices = 6; /* Face has 6 vertices */
3511: break;
3512: case 12: /* hex cohesive Lagrange cells */
3513: *numFaceVertices = 6; /* Face has 6 vertices */
3514: break;
3515: case 18: /* quadratic tet cohesive Lagrange cells */
3516: *numFaceVertices = 6; /* Face has 6 vertices */
3517: break;
3518: case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3519: *numFaceVertices = 9; /* Face has 9 vertices */
3520: break;
3521: default:
3522: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3523: }
3524: break;
3525: default:
3526: SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3527: }
3528: return(0);
3529: }
3531: /*@
3532: DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
3534: Not Collective
3536: Input Parameter:
3537: . dm - The DMPlex object
3539: Output Parameter:
3540: . depthLabel - The DMLabel recording point depth
3542: Level: developer
3544: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3545: @*/
3546: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3547: {
3553: if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3554: *depthLabel = dm->depthLabel;
3555: return(0);
3556: }
3558: /*@
3559: DMPlexGetDepth - Get the depth of the DAG representing this mesh
3561: Not Collective
3563: Input Parameter:
3564: . dm - The DMPlex object
3566: Output Parameter:
3567: . depth - The number of strata (breadth first levels) in the DAG
3569: Level: developer
3571: Notes:
3572: This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
3573: The point depth is described more in detail in DMPlexSymmetrize().
3575: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexSymmetrize()
3576: @*/
3577: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3578: {
3579: DMLabel label;
3580: PetscInt d = 0;
3586: DMPlexGetDepthLabel(dm, &label);
3587: if (label) {DMLabelGetNumValues(label, &d);}
3588: *depth = d-1;
3589: return(0);
3590: }
3592: /*@
3593: DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
3595: Not Collective
3597: Input Parameters:
3598: + dm - The DMPlex object
3599: - stratumValue - The requested depth
3601: Output Parameters:
3602: + start - The first point at this depth
3603: - end - One beyond the last point at this depth
3605: Notes:
3606: Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points,
3607: often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
3608: higher dimension, e.g., "edges".
3610: Level: developer
3612: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3613: @*/
3614: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3615: {
3616: DMLabel label;
3617: PetscInt pStart, pEnd;
3624: DMPlexGetChart(dm, &pStart, &pEnd);
3625: if (pStart == pEnd) return(0);
3626: if (stratumValue < 0) {
3627: if (start) *start = pStart;
3628: if (end) *end = pEnd;
3629: return(0);
3630: }
3631: DMPlexGetDepthLabel(dm, &label);
3632: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3633: DMLabelGetStratumBounds(label, stratumValue, start, end);
3634: return(0);
3635: }
3637: /*@
3638: DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3640: Not Collective
3642: Input Parameters:
3643: + dm - The DMPlex object
3644: - stratumValue - The requested height
3646: Output Parameters:
3647: + start - The first point at this height
3648: - end - One beyond the last point at this height
3650: Notes:
3651: Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension
3652: points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height
3653: stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
3655: Level: developer
3657: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3658: @*/
3659: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3660: {
3661: DMLabel label;
3662: PetscInt depth, pStart, pEnd;
3669: DMPlexGetChart(dm, &pStart, &pEnd);
3670: if (pStart == pEnd) return(0);
3671: if (stratumValue < 0) {
3672: if (start) *start = pStart;
3673: if (end) *end = pEnd;
3674: return(0);
3675: }
3676: DMPlexGetDepthLabel(dm, &label);
3677: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3678: DMLabelGetNumValues(label, &depth);
3679: DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3680: return(0);
3681: }
3683: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3684: {
3685: PetscSection section, s;
3686: Mat m;
3687: PetscInt maxHeight;
3691: DMClone(dm, cdm);
3692: DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3693: DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3694: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
3695: DMSetLocalSection(*cdm, section);
3696: PetscSectionDestroy(§ion);
3697: PetscSectionCreate(PETSC_COMM_SELF, &s);
3698: MatCreate(PETSC_COMM_SELF, &m);
3699: DMSetDefaultConstraints(*cdm, s, m);
3700: PetscSectionDestroy(&s);
3701: MatDestroy(&m);
3703: DMSetNumFields(*cdm, 1);
3704: DMCreateDS(*cdm);
3705: return(0);
3706: }
3708: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3709: {
3710: Vec coordsLocal;
3711: DM coordsDM;
3715: *field = NULL;
3716: DMGetCoordinatesLocal(dm,&coordsLocal);
3717: DMGetCoordinateDM(dm,&coordsDM);
3718: if (coordsLocal && coordsDM) {
3719: DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3720: }
3721: return(0);
3722: }
3724: /*@C
3725: DMPlexGetConeSection - Return a section which describes the layout of cone data
3727: Not Collective
3729: Input Parameters:
3730: . dm - The DMPlex object
3732: Output Parameter:
3733: . section - The PetscSection object
3735: Level: developer
3737: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3738: @*/
3739: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3740: {
3741: DM_Plex *mesh = (DM_Plex*) dm->data;
3745: if (section) *section = mesh->coneSection;
3746: return(0);
3747: }
3749: /*@C
3750: DMPlexGetSupportSection - Return a section which describes the layout of support data
3752: Not Collective
3754: Input Parameters:
3755: . dm - The DMPlex object
3757: Output Parameter:
3758: . section - The PetscSection object
3760: Level: developer
3762: .seealso: DMPlexGetConeSection()
3763: @*/
3764: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3765: {
3766: DM_Plex *mesh = (DM_Plex*) dm->data;
3770: if (section) *section = mesh->supportSection;
3771: return(0);
3772: }
3774: /*@C
3775: DMPlexGetCones - Return cone data
3777: Not Collective
3779: Input Parameters:
3780: . dm - The DMPlex object
3782: Output Parameter:
3783: . cones - The cone for each point
3785: Level: developer
3787: .seealso: DMPlexGetConeSection()
3788: @*/
3789: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3790: {
3791: DM_Plex *mesh = (DM_Plex*) dm->data;
3795: if (cones) *cones = mesh->cones;
3796: return(0);
3797: }
3799: /*@C
3800: DMPlexGetConeOrientations - Return cone orientation data
3802: Not Collective
3804: Input Parameters:
3805: . dm - The DMPlex object
3807: Output Parameter:
3808: . coneOrientations - The cone orientation for each point
3810: Level: developer
3812: .seealso: DMPlexGetConeSection()
3813: @*/
3814: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3815: {
3816: DM_Plex *mesh = (DM_Plex*) dm->data;
3820: if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3821: return(0);
3822: }
3824: /******************************** FEM Support **********************************/
3826: /*
3827: Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point
3828: representing a line in the section.
3829: */
3830: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
3831: {
3835: PetscSectionGetFieldComponents(section, field, Nc);
3836: if (line < 0) {
3837: *k = 0;
3838: *Nc = 0;
3839: } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */
3840: *k = 1;
3841: } else { /* Assume the full interpolated mesh is in the chart; lines in particular */
3842: /* An order k SEM disc has k-1 dofs on an edge */
3843: PetscSectionGetFieldDof(section, line, field, k);
3844: *k = *k / *Nc + 1;
3845: }
3846: return(0);
3847: }
3849: /*@
3851: DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
3852: lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
3853: section provided (or the section of the DM).
3855: Input Parameters:
3856: + dm - The DM
3857: . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
3858: - section - The PetscSection to reorder, or NULL for the default section
3860: Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
3861: degree of the basis.
3863: Example:
3864: A typical interpolated single-quad mesh might order points as
3865: .vb
3866: [c0, v1, v2, v3, v4, e5, e6, e7, e8]
3868: v4 -- e6 -- v3
3869: | |
3870: e7 c0 e8
3871: | |
3872: v1 -- e5 -- v2
3873: .ve
3875: (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign
3876: dofs in the order of points, e.g.,
3877: .vb
3878: c0 -> [0,1,2,3]
3879: v1 -> [4]
3880: ...
3881: e5 -> [8, 9]
3882: .ve
3884: which corresponds to the dofs
3885: .vb
3886: 6 10 11 7
3887: 13 2 3 15
3888: 12 0 1 14
3889: 4 8 9 5
3890: .ve
3892: The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
3893: .vb
3894: 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
3895: .ve
3897: After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
3898: .vb
3899: 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
3900: .ve
3902: Level: developer
3904: .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection()
3905: @*/
3906: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
3907: {
3908: DMLabel label;
3909: PetscInt *perm;
3910: PetscInt dim, depth = -1, eStart = -1, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3911: PetscBool vertexchart;
3915: DMGetDimension(dm, &dim);
3916: if (dim < 1) return(0);
3917: if (point < 0) {
3918: PetscInt sStart,sEnd;
3920: DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);
3921: point = sEnd-sStart ? sStart : point;
3922: }
3923: DMPlexGetDepthLabel(dm, &label);
3924: if (point >= 0) { DMLabelGetValue(label, point, &depth); }
3925: if (!section) {DMGetLocalSection(dm, §ion);}
3926: if (depth == 1) {eStart = point;}
3927: else if (depth == dim) {
3928: const PetscInt *cone;
3930: DMPlexGetCone(dm, point, &cone);
3931: if (dim == 2) eStart = cone[0];
3932: else if (dim == 3) {
3933: const PetscInt *cone2;
3934: DMPlexGetCone(dm, cone[0], &cone2);
3935: eStart = cone2[0];
3936: } 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);
3937: } else if (depth >= 0) 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);
3938: { /* Determine whether the chart covers all points or just vertices. */
3939: PetscInt pStart,pEnd,cStart,cEnd;
3940: DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);
3941: PetscSectionGetChart(section,&cStart,&cEnd);
3942: if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
3943: else vertexchart = PETSC_FALSE; /* Assume all interpolated points are in chart */
3944: }
3945: PetscSectionGetNumFields(section, &Nf);
3946: for (f = 0; f < Nf; ++f) {
3947: PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3948: size += PetscPowInt(k+1, dim)*Nc;
3949: }
3950: PetscMalloc1(size, &perm);
3951: for (f = 0; f < Nf; ++f) {
3952: switch (dim) {
3953: case 1:
3954: PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3955: /*
3956: Original ordering is [ edge of length k-1; vtx0; vtx1 ]
3957: We want [ vtx0; edge of length k-1; vtx1 ]
3958: */
3959: for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
3960: for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
3961: for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
3962: foffset = offset;
3963: break;
3964: case 2:
3965: /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3966: PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3967: /* The SEM order is
3969: v_lb, {e_b}, v_rb,
3970: e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3971: v_lt, reverse {e_t}, v_rt
3972: */
3973: {
3974: const PetscInt of = 0;
3975: const PetscInt oeb = of + PetscSqr(k-1);
3976: const PetscInt oer = oeb + (k-1);
3977: const PetscInt oet = oer + (k-1);
3978: const PetscInt oel = oet + (k-1);
3979: const PetscInt ovlb = oel + (k-1);
3980: const PetscInt ovrb = ovlb + 1;
3981: const PetscInt ovrt = ovrb + 1;
3982: const PetscInt ovlt = ovrt + 1;
3983: PetscInt o;
3985: /* bottom */
3986: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3987: for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3988: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3989: /* middle */
3990: for (i = 0; i < k-1; ++i) {
3991: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3992: 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;
3993: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3994: }
3995: /* top */
3996: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3997: for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3998: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3999: foffset = offset;
4000: }
4001: break;
4002: case 3:
4003: /* The original hex closure is
4005: {c,
4006: f_b, f_t, f_f, f_b, f_r, f_l,
4007: e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb,
4008: v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
4009: */
4010: PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
4011: /* The SEM order is
4012: Bottom Slice
4013: v_blf, {e^{(k-1)-n}_bf}, v_brf,
4014: e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
4015: v_blb, {e_bb}, v_brb,
4017: Middle Slice (j)
4018: {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
4019: f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
4020: e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
4022: Top Slice
4023: v_tlf, {e_tf}, v_trf,
4024: e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
4025: v_tlb, {e^{(k-1)-n}_tb}, v_trb,
4026: */
4027: {
4028: const PetscInt oc = 0;
4029: const PetscInt ofb = oc + PetscSqr(k-1)*(k-1);
4030: const PetscInt oft = ofb + PetscSqr(k-1);
4031: const PetscInt off = oft + PetscSqr(k-1);
4032: const PetscInt ofk = off + PetscSqr(k-1);
4033: const PetscInt ofr = ofk + PetscSqr(k-1);
4034: const PetscInt ofl = ofr + PetscSqr(k-1);
4035: const PetscInt oebl = ofl + PetscSqr(k-1);
4036: const PetscInt oebb = oebl + (k-1);
4037: const PetscInt oebr = oebb + (k-1);
4038: const PetscInt oebf = oebr + (k-1);
4039: const PetscInt oetf = oebf + (k-1);
4040: const PetscInt oetr = oetf + (k-1);
4041: const PetscInt oetb = oetr + (k-1);
4042: const PetscInt oetl = oetb + (k-1);
4043: const PetscInt oerf = oetl + (k-1);
4044: const PetscInt oelf = oerf + (k-1);
4045: const PetscInt oelb = oelf + (k-1);
4046: const PetscInt oerb = oelb + (k-1);
4047: const PetscInt ovblf = oerb + (k-1);
4048: const PetscInt ovblb = ovblf + 1;
4049: const PetscInt ovbrb = ovblb + 1;
4050: const PetscInt ovbrf = ovbrb + 1;
4051: const PetscInt ovtlf = ovbrf + 1;
4052: const PetscInt ovtrf = ovtlf + 1;
4053: const PetscInt ovtrb = ovtrf + 1;
4054: const PetscInt ovtlb = ovtrb + 1;
4055: PetscInt o, n;
4057: /* Bottom Slice */
4058: /* bottom */
4059: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
4060: for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4061: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
4062: /* middle */
4063: for (i = 0; i < k-1; ++i) {
4064: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
4065: 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;}
4066: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
4067: }
4068: /* top */
4069: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
4070: for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4071: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
4073: /* Middle Slice */
4074: for (j = 0; j < k-1; ++j) {
4075: /* bottom */
4076: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
4077: 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;
4078: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
4079: /* middle */
4080: for (i = 0; i < k-1; ++i) {
4081: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
4082: 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;
4083: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
4084: }
4085: /* top */
4086: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
4087: 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;
4088: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
4089: }
4091: /* Top Slice */
4092: /* bottom */
4093: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
4094: for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4095: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
4096: /* middle */
4097: for (i = 0; i < k-1; ++i) {
4098: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
4099: for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
4100: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
4101: }
4102: /* top */
4103: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
4104: for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4105: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
4107: foffset = offset;
4108: }
4109: break;
4110: default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
4111: }
4112: }
4113: if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
4114: /* Check permutation */
4115: {
4116: PetscInt *check;
4118: PetscMalloc1(size, &check);
4119: 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]);}
4120: for (i = 0; i < size; ++i) check[perm[i]] = i;
4121: for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
4122: PetscFree(check);
4123: }
4124: PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
4125: return(0);
4126: }
4128: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
4129: {
4130: PetscDS prob;
4131: PetscInt depth, Nf, h;
4132: DMLabel label;
4136: DMGetDS(dm, &prob);
4137: Nf = prob->Nf;
4138: label = dm->depthLabel;
4139: *dspace = NULL;
4140: if (field < Nf) {
4141: PetscObject disc = prob->disc[field];
4143: if (disc->classid == PETSCFE_CLASSID) {
4144: PetscDualSpace dsp;
4146: PetscFEGetDualSpace((PetscFE)disc,&dsp);
4147: DMLabelGetNumValues(label,&depth);
4148: DMLabelGetValue(label,point,&h);
4149: h = depth - 1 - h;
4150: if (h) {
4151: PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
4152: } else {
4153: *dspace = dsp;
4154: }
4155: }
4156: }
4157: return(0);
4158: }
4161: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4162: {
4163: PetscScalar *array, *vArray;
4164: const PetscInt *cone, *coneO;
4165: PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0;
4166: PetscErrorCode ierr;
4169: PetscSectionGetChart(section, &pStart, &pEnd);
4170: DMPlexGetConeSize(dm, point, &numPoints);
4171: DMPlexGetCone(dm, point, &cone);
4172: DMPlexGetConeOrientation(dm, point, &coneO);
4173: if (!values || !*values) {
4174: if ((point >= pStart) && (point < pEnd)) {
4175: PetscInt dof;
4177: PetscSectionGetDof(section, point, &dof);
4178: size += dof;
4179: }
4180: for (p = 0; p < numPoints; ++p) {
4181: const PetscInt cp = cone[p];
4182: PetscInt dof;
4184: if ((cp < pStart) || (cp >= pEnd)) continue;
4185: PetscSectionGetDof(section, cp, &dof);
4186: size += dof;
4187: }
4188: if (!values) {
4189: if (csize) *csize = size;
4190: return(0);
4191: }
4192: DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
4193: } else {
4194: array = *values;
4195: }
4196: size = 0;
4197: VecGetArray(v, &vArray);
4198: if ((point >= pStart) && (point < pEnd)) {
4199: PetscInt dof, off, d;
4200: PetscScalar *varr;
4202: PetscSectionGetDof(section, point, &dof);
4203: PetscSectionGetOffset(section, point, &off);
4204: varr = &vArray[off];
4205: for (d = 0; d < dof; ++d, ++offset) {
4206: array[offset] = varr[d];
4207: }
4208: size += dof;
4209: }
4210: for (p = 0; p < numPoints; ++p) {
4211: const PetscInt cp = cone[p];
4212: PetscInt o = coneO[p];
4213: PetscInt dof, off, d;
4214: PetscScalar *varr;
4216: if ((cp < pStart) || (cp >= pEnd)) continue;
4217: PetscSectionGetDof(section, cp, &dof);
4218: PetscSectionGetOffset(section, cp, &off);
4219: varr = &vArray[off];
4220: if (o >= 0) {
4221: for (d = 0; d < dof; ++d, ++offset) {
4222: array[offset] = varr[d];
4223: }
4224: } else {
4225: for (d = dof-1; d >= 0; --d, ++offset) {
4226: array[offset] = varr[d];
4227: }
4228: }
4229: size += dof;
4230: }
4231: VecRestoreArray(v, &vArray);
4232: if (!*values) {
4233: if (csize) *csize = size;
4234: *values = array;
4235: } else {
4236: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4237: *csize = size;
4238: }
4239: return(0);
4240: }
4242: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4243: {
4244: const PetscInt *cla;
4245: PetscInt np, *pts = NULL;
4249: PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
4250: if (!*clPoints) {
4251: PetscInt pStart, pEnd, p, q;
4253: PetscSectionGetChart(section, &pStart, &pEnd);
4254: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
4255: /* Compress out points not in the section */
4256: for (p = 0, q = 0; p < np; p++) {
4257: PetscInt r = pts[2*p];
4258: if ((r >= pStart) && (r < pEnd)) {
4259: pts[q*2] = r;
4260: pts[q*2+1] = pts[2*p+1];
4261: ++q;
4262: }
4263: }
4264: np = q;
4265: cla = NULL;
4266: } else {
4267: PetscInt dof, off;
4269: PetscSectionGetDof(*clSec, point, &dof);
4270: PetscSectionGetOffset(*clSec, point, &off);
4271: ISGetIndices(*clPoints, &cla);
4272: np = dof/2;
4273: pts = (PetscInt *) &cla[off];
4274: }
4275: *numPoints = np;
4276: *points = pts;
4277: *clp = cla;
4279: return(0);
4280: }
4282: PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4283: {
4287: if (!*clPoints) {
4288: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
4289: } else {
4290: ISRestoreIndices(*clPoints, clp);
4291: }
4292: *numPoints = 0;
4293: *points = NULL;
4294: *clSec = NULL;
4295: *clPoints = NULL;
4296: *clp = NULL;
4297: return(0);
4298: }
4300: 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[])
4301: {
4302: PetscInt offset = 0, p;
4303: const PetscInt **perms = NULL;
4304: const PetscScalar **flips = NULL;
4305: PetscErrorCode ierr;
4308: *size = 0;
4309: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4310: for (p = 0; p < numPoints; p++) {
4311: const PetscInt point = points[2*p];
4312: const PetscInt *perm = perms ? perms[p] : NULL;
4313: const PetscScalar *flip = flips ? flips[p] : NULL;
4314: PetscInt dof, off, d;
4315: const PetscScalar *varr;
4317: PetscSectionGetDof(section, point, &dof);
4318: PetscSectionGetOffset(section, point, &off);
4319: varr = &vArray[off];
4320: if (clperm) {
4321: if (perm) {
4322: for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
4323: } else {
4324: for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d];
4325: }
4326: if (flip) {
4327: for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d];
4328: }
4329: } else {
4330: if (perm) {
4331: for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
4332: } else {
4333: for (d = 0; d < dof; d++) array[offset + d ] = varr[d];
4334: }
4335: if (flip) {
4336: for (d = 0; d < dof; d++) array[offset + d ] *= flip[d];
4337: }
4338: }
4339: offset += dof;
4340: }
4341: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4342: *size = offset;
4343: return(0);
4344: }
4346: 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[])
4347: {
4348: PetscInt offset = 0, f;
4349: PetscErrorCode ierr;
4352: *size = 0;
4353: for (f = 0; f < numFields; ++f) {
4354: PetscInt p;
4355: const PetscInt **perms = NULL;
4356: const PetscScalar **flips = NULL;
4358: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4359: for (p = 0; p < numPoints; p++) {
4360: const PetscInt point = points[2*p];
4361: PetscInt fdof, foff, b;
4362: const PetscScalar *varr;
4363: const PetscInt *perm = perms ? perms[p] : NULL;
4364: const PetscScalar *flip = flips ? flips[p] : NULL;
4366: PetscSectionGetFieldDof(section, point, f, &fdof);
4367: PetscSectionGetFieldOffset(section, point, f, &foff);
4368: varr = &vArray[foff];
4369: if (clperm) {
4370: if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}}
4371: else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}}
4372: if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}}
4373: } else {
4374: if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}}
4375: else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}}
4376: if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}}
4377: }
4378: offset += fdof;
4379: }
4380: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4381: }
4382: *size = offset;
4383: return(0);
4384: }
4386: /*@C
4387: DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4389: Not collective
4391: Input Parameters:
4392: + dm - The DM
4393: . section - The section describing the layout in v, or NULL to use the default section
4394: . v - The local vector
4395: . point - The point in the DM
4396: . csize - The size of the input values array, or NULL
4397: - values - An array to use for the values, or NULL to have it allocated automatically
4399: Output Parameters:
4400: + csize - The number of values in the closure
4401: - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4403: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4404: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4405: $ assembly function, and a user may already have allocated storage for this operation.
4406: $
4407: $ A typical use could be
4408: $
4409: $ values = NULL;
4410: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4411: $ for (cl = 0; cl < clSize; ++cl) {
4412: $ <Compute on closure>
4413: $ }
4414: $ DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4415: $
4416: $ or
4417: $
4418: $ PetscMalloc1(clMaxSize, &values);
4419: $ for (p = pStart; p < pEnd; ++p) {
4420: $ clSize = clMaxSize;
4421: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4422: $ for (cl = 0; cl < clSize; ++cl) {
4423: $ <Compute on closure>
4424: $ }
4425: $ }
4426: $ PetscFree(values);
4428: Fortran Notes:
4429: Since it returns an array, this routine is only available in Fortran 90, and you must
4430: include petsc.h90 in your code.
4432: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4434: Level: intermediate
4436: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4437: @*/
4438: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4439: {
4440: PetscSection clSection;
4441: IS clPoints;
4442: PetscScalar *array;
4443: const PetscScalar *vArray;
4444: PetscInt *points = NULL;
4445: const PetscInt *clp, *perm;
4446: PetscInt depth, numFields, numPoints, size;
4447: PetscErrorCode ierr;
4451: if (!section) {DMGetLocalSection(dm, §ion);}
4454: DMPlexGetDepth(dm, &depth);
4455: PetscSectionGetNumFields(section, &numFields);
4456: if (depth == 1 && numFields < 2) {
4457: DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4458: return(0);
4459: }
4460: /* Get points */
4461: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4462: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4463: /* Get array */
4464: if (!values || !*values) {
4465: PetscInt asize = 0, dof, p;
4467: for (p = 0; p < numPoints*2; p += 2) {
4468: PetscSectionGetDof(section, points[p], &dof);
4469: asize += dof;
4470: }
4471: if (!values) {
4472: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4473: if (csize) *csize = asize;
4474: return(0);
4475: }
4476: DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4477: } else {
4478: array = *values;
4479: }
4480: VecGetArrayRead(v, &vArray);
4481: /* Get values */
4482: if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4483: else {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4484: /* Cleanup points */
4485: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4486: /* Cleanup array */
4487: VecRestoreArrayRead(v, &vArray);
4488: if (!*values) {
4489: if (csize) *csize = size;
4490: *values = array;
4491: } else {
4492: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4493: *csize = size;
4494: }
4495: return(0);
4496: }
4498: /*@C
4499: DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4501: Not collective
4503: Input Parameters:
4504: + dm - The DM
4505: . section - The section describing the layout in v, or NULL to use the default section
4506: . v - The local vector
4507: . point - The point in the DM
4508: . csize - The number of values in the closure, or NULL
4509: - values - The array of values, which is a borrowed array and should not be freed
4511: Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4513: Fortran Notes:
4514: Since it returns an array, this routine is only available in Fortran 90, and you must
4515: include petsc.h90 in your code.
4517: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4519: Level: intermediate
4521: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4522: @*/
4523: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4524: {
4525: PetscInt size = 0;
4529: /* Should work without recalculating size */
4530: DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4531: *values = NULL;
4532: return(0);
4533: }
4535: PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;}
4536: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;}
4538: 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[])
4539: {
4540: PetscInt cdof; /* The number of constraints on this point */
4541: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4542: PetscScalar *a;
4543: PetscInt off, cind = 0, k;
4544: PetscErrorCode ierr;
4547: PetscSectionGetConstraintDof(section, point, &cdof);
4548: PetscSectionGetOffset(section, point, &off);
4549: a = &array[off];
4550: if (!cdof || setBC) {
4551: if (clperm) {
4552: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4553: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}}
4554: } else {
4555: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4556: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}}
4557: }
4558: } else {
4559: PetscSectionGetConstraintIndices(section, point, &cdofs);
4560: if (clperm) {
4561: if (perm) {for (k = 0; k < dof; ++k) {
4562: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4563: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4564: }
4565: } else {
4566: for (k = 0; k < dof; ++k) {
4567: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4568: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4569: }
4570: }
4571: } else {
4572: if (perm) {
4573: for (k = 0; k < dof; ++k) {
4574: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4575: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4576: }
4577: } else {
4578: for (k = 0; k < dof; ++k) {
4579: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4580: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4581: }
4582: }
4583: }
4584: }
4585: return(0);
4586: }
4588: 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[])
4589: {
4590: PetscInt cdof; /* The number of constraints on this point */
4591: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4592: PetscScalar *a;
4593: PetscInt off, cind = 0, k;
4594: PetscErrorCode ierr;
4597: PetscSectionGetConstraintDof(section, point, &cdof);
4598: PetscSectionGetOffset(section, point, &off);
4599: a = &array[off];
4600: if (cdof) {
4601: PetscSectionGetConstraintIndices(section, point, &cdofs);
4602: if (clperm) {
4603: if (perm) {
4604: for (k = 0; k < dof; ++k) {
4605: if ((cind < cdof) && (k == cdofs[cind])) {
4606: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4607: cind++;
4608: }
4609: }
4610: } else {
4611: for (k = 0; k < dof; ++k) {
4612: if ((cind < cdof) && (k == cdofs[cind])) {
4613: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4614: cind++;
4615: }
4616: }
4617: }
4618: } else {
4619: if (perm) {
4620: for (k = 0; k < dof; ++k) {
4621: if ((cind < cdof) && (k == cdofs[cind])) {
4622: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4623: cind++;
4624: }
4625: }
4626: } else {
4627: for (k = 0; k < dof; ++k) {
4628: if ((cind < cdof) && (k == cdofs[cind])) {
4629: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4630: cind++;
4631: }
4632: }
4633: }
4634: }
4635: }
4636: return(0);
4637: }
4639: 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[])
4640: {
4641: PetscScalar *a;
4642: PetscInt fdof, foff, fcdof, foffset = *offset;
4643: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4644: PetscInt cind = 0, b;
4645: PetscErrorCode ierr;
4648: PetscSectionGetFieldDof(section, point, f, &fdof);
4649: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4650: PetscSectionGetFieldOffset(section, point, f, &foff);
4651: a = &array[foff];
4652: if (!fcdof || setBC) {
4653: if (clperm) {
4654: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4655: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}}
4656: } else {
4657: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4658: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}}
4659: }
4660: } else {
4661: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4662: if (clperm) {
4663: if (perm) {
4664: for (b = 0; b < fdof; b++) {
4665: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4666: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4667: }
4668: } else {
4669: for (b = 0; b < fdof; b++) {
4670: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4671: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4672: }
4673: }
4674: } else {
4675: if (perm) {
4676: for (b = 0; b < fdof; b++) {
4677: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4678: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4679: }
4680: } else {
4681: for (b = 0; b < fdof; b++) {
4682: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4683: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4684: }
4685: }
4686: }
4687: }
4688: *offset += fdof;
4689: return(0);
4690: }
4692: 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[])
4693: {
4694: PetscScalar *a;
4695: PetscInt fdof, foff, fcdof, foffset = *offset;
4696: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4697: PetscInt cind = 0, ncind = 0, b;
4698: PetscBool ncSet, fcSet;
4699: PetscErrorCode ierr;
4702: PetscSectionGetFieldDof(section, point, f, &fdof);
4703: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4704: PetscSectionGetFieldOffset(section, point, f, &foff);
4705: a = &array[foff];
4706: if (fcdof) {
4707: /* We just override fcdof and fcdofs with Ncc and comps */
4708: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4709: if (clperm) {
4710: if (perm) {
4711: if (comps) {
4712: for (b = 0; b < fdof; b++) {
4713: ncSet = fcSet = PETSC_FALSE;
4714: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4715: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4716: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4717: }
4718: } else {
4719: for (b = 0; b < fdof; b++) {
4720: if ((cind < fcdof) && (b == fcdofs[cind])) {
4721: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4722: ++cind;
4723: }
4724: }
4725: }
4726: } else {
4727: if (comps) {
4728: for (b = 0; b < fdof; b++) {
4729: ncSet = fcSet = PETSC_FALSE;
4730: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4731: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4732: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}
4733: }
4734: } else {
4735: for (b = 0; b < fdof; b++) {
4736: if ((cind < fcdof) && (b == fcdofs[cind])) {
4737: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4738: ++cind;
4739: }
4740: }
4741: }
4742: }
4743: } else {
4744: if (perm) {
4745: if (comps) {
4746: for (b = 0; b < fdof; b++) {
4747: ncSet = fcSet = PETSC_FALSE;
4748: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4749: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4750: if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4751: }
4752: } else {
4753: for (b = 0; b < fdof; b++) {
4754: if ((cind < fcdof) && (b == fcdofs[cind])) {
4755: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4756: ++cind;
4757: }
4758: }
4759: }
4760: } else {
4761: if (comps) {
4762: for (b = 0; b < fdof; b++) {
4763: ncSet = fcSet = PETSC_FALSE;
4764: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4765: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4766: if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}
4767: }
4768: } else {
4769: for (b = 0; b < fdof; b++) {
4770: if ((cind < fcdof) && (b == fcdofs[cind])) {
4771: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4772: ++cind;
4773: }
4774: }
4775: }
4776: }
4777: }
4778: }
4779: *offset += fdof;
4780: return(0);
4781: }
4783: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4784: {
4785: PetscScalar *array;
4786: const PetscInt *cone, *coneO;
4787: PetscInt pStart, pEnd, p, numPoints, off, dof;
4788: PetscErrorCode ierr;
4791: PetscSectionGetChart(section, &pStart, &pEnd);
4792: DMPlexGetConeSize(dm, point, &numPoints);
4793: DMPlexGetCone(dm, point, &cone);
4794: DMPlexGetConeOrientation(dm, point, &coneO);
4795: VecGetArray(v, &array);
4796: for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4797: const PetscInt cp = !p ? point : cone[p-1];
4798: const PetscInt o = !p ? 0 : coneO[p-1];
4800: if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4801: PetscSectionGetDof(section, cp, &dof);
4802: /* ADD_VALUES */
4803: {
4804: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4805: PetscScalar *a;
4806: PetscInt cdof, coff, cind = 0, k;
4808: PetscSectionGetConstraintDof(section, cp, &cdof);
4809: PetscSectionGetOffset(section, cp, &coff);
4810: a = &array[coff];
4811: if (!cdof) {
4812: if (o >= 0) {
4813: for (k = 0; k < dof; ++k) {
4814: a[k] += values[off+k];
4815: }
4816: } else {
4817: for (k = 0; k < dof; ++k) {
4818: a[k] += values[off+dof-k-1];
4819: }
4820: }
4821: } else {
4822: PetscSectionGetConstraintIndices(section, cp, &cdofs);
4823: if (o >= 0) {
4824: for (k = 0; k < dof; ++k) {
4825: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4826: a[k] += values[off+k];
4827: }
4828: } else {
4829: for (k = 0; k < dof; ++k) {
4830: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4831: a[k] += values[off+dof-k-1];
4832: }
4833: }
4834: }
4835: }
4836: }
4837: VecRestoreArray(v, &array);
4838: return(0);
4839: }
4841: /*@C
4842: DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4844: Not collective
4846: Input Parameters:
4847: + dm - The DM
4848: . section - The section describing the layout in v, or NULL to use the default section
4849: . v - The local vector
4850: . point - The point in the DM
4851: . values - The array of values
4852: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4853: where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
4855: Fortran Notes:
4856: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4858: Level: intermediate
4860: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4861: @*/
4862: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4863: {
4864: PetscSection clSection;
4865: IS clPoints;
4866: PetscScalar *array;
4867: PetscInt *points = NULL;
4868: const PetscInt *clp, *clperm;
4869: PetscInt depth, numFields, numPoints, p;
4870: PetscErrorCode ierr;
4874: if (!section) {DMGetLocalSection(dm, §ion);}
4877: DMPlexGetDepth(dm, &depth);
4878: PetscSectionGetNumFields(section, &numFields);
4879: if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4880: DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4881: return(0);
4882: }
4883: /* Get points */
4884: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4885: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4886: /* Get array */
4887: VecGetArray(v, &array);
4888: /* Get values */
4889: if (numFields > 0) {
4890: PetscInt offset = 0, f;
4891: for (f = 0; f < numFields; ++f) {
4892: const PetscInt **perms = NULL;
4893: const PetscScalar **flips = NULL;
4895: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4896: switch (mode) {
4897: case INSERT_VALUES:
4898: for (p = 0; p < numPoints; p++) {
4899: const PetscInt point = points[2*p];
4900: const PetscInt *perm = perms ? perms[p] : NULL;
4901: const PetscScalar *flip = flips ? flips[p] : NULL;
4902: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4903: } break;
4904: case INSERT_ALL_VALUES:
4905: for (p = 0; p < numPoints; p++) {
4906: const PetscInt point = points[2*p];
4907: const PetscInt *perm = perms ? perms[p] : NULL;
4908: const PetscScalar *flip = flips ? flips[p] : NULL;
4909: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4910: } break;
4911: case INSERT_BC_VALUES:
4912: for (p = 0; p < numPoints; p++) {
4913: const PetscInt point = points[2*p];
4914: const PetscInt *perm = perms ? perms[p] : NULL;
4915: const PetscScalar *flip = flips ? flips[p] : NULL;
4916: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4917: } break;
4918: case ADD_VALUES:
4919: for (p = 0; p < numPoints; p++) {
4920: const PetscInt point = points[2*p];
4921: const PetscInt *perm = perms ? perms[p] : NULL;
4922: const PetscScalar *flip = flips ? flips[p] : NULL;
4923: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4924: } break;
4925: case ADD_ALL_VALUES:
4926: for (p = 0; p < numPoints; p++) {
4927: const PetscInt point = points[2*p];
4928: const PetscInt *perm = perms ? perms[p] : NULL;
4929: const PetscScalar *flip = flips ? flips[p] : NULL;
4930: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4931: } break;
4932: case ADD_BC_VALUES:
4933: for (p = 0; p < numPoints; p++) {
4934: const PetscInt point = points[2*p];
4935: const PetscInt *perm = perms ? perms[p] : NULL;
4936: const PetscScalar *flip = flips ? flips[p] : NULL;
4937: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4938: } break;
4939: default:
4940: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4941: }
4942: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4943: }
4944: } else {
4945: PetscInt dof, off;
4946: const PetscInt **perms = NULL;
4947: const PetscScalar **flips = NULL;
4949: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4950: switch (mode) {
4951: case INSERT_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, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4958: } break;
4959: case INSERT_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, insert, PETSC_TRUE, perm, flip, clperm, values, off, array);
4966: } break;
4967: case INSERT_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, insert, perm, flip, clperm, values, off, array);
4974: } break;
4975: case ADD_VALUES:
4976: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4977: const PetscInt point = points[2*p];
4978: const PetscInt *perm = perms ? perms[p] : NULL;
4979: const PetscScalar *flip = flips ? flips[p] : NULL;
4980: PetscSectionGetDof(section, point, &dof);
4981: updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array);
4982: } break;
4983: case ADD_ALL_VALUES:
4984: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4985: const PetscInt point = points[2*p];
4986: const PetscInt *perm = perms ? perms[p] : NULL;
4987: const PetscScalar *flip = flips ? flips[p] : NULL;
4988: PetscSectionGetDof(section, point, &dof);
4989: updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array);
4990: } break;
4991: case ADD_BC_VALUES:
4992: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4993: const PetscInt point = points[2*p];
4994: const PetscInt *perm = perms ? perms[p] : NULL;
4995: const PetscScalar *flip = flips ? flips[p] : NULL;
4996: PetscSectionGetDof(section, point, &dof);
4997: updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array);
4998: } break;
4999: default:
5000: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5001: }
5002: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
5003: }
5004: /* Cleanup points */
5005: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5006: /* Cleanup array */
5007: VecRestoreArray(v, &array);
5008: return(0);
5009: }
5011: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
5012: {
5013: PetscSection clSection;
5014: IS clPoints;
5015: PetscScalar *array;
5016: PetscInt *points = NULL;
5017: const PetscInt *clp, *clperm;
5018: PetscInt numFields, numPoints, p;
5019: PetscInt offset = 0, f;
5020: PetscErrorCode ierr;
5024: if (!section) {DMGetLocalSection(dm, §ion);}
5027: PetscSectionGetNumFields(section, &numFields);
5028: /* Get points */
5029: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5030: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5031: /* Get array */
5032: VecGetArray(v, &array);
5033: /* Get values */
5034: for (f = 0; f < numFields; ++f) {
5035: const PetscInt **perms = NULL;
5036: const PetscScalar **flips = NULL;
5038: if (!fieldActive[f]) {
5039: for (p = 0; p < numPoints*2; p += 2) {
5040: PetscInt fdof;
5041: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5042: offset += fdof;
5043: }
5044: continue;
5045: }
5046: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5047: switch (mode) {
5048: case INSERT_VALUES:
5049: for (p = 0; p < numPoints; p++) {
5050: const PetscInt point = points[2*p];
5051: const PetscInt *perm = perms ? perms[p] : NULL;
5052: const PetscScalar *flip = flips ? flips[p] : NULL;
5053: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5054: } break;
5055: case INSERT_ALL_VALUES:
5056: for (p = 0; p < numPoints; p++) {
5057: const PetscInt point = points[2*p];
5058: const PetscInt *perm = perms ? perms[p] : NULL;
5059: const PetscScalar *flip = flips ? flips[p] : NULL;
5060: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5061: } break;
5062: case INSERT_BC_VALUES:
5063: for (p = 0; p < numPoints; p++) {
5064: const PetscInt point = points[2*p];
5065: const PetscInt *perm = perms ? perms[p] : NULL;
5066: const PetscScalar *flip = flips ? flips[p] : NULL;
5067: updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
5068: } break;
5069: case ADD_VALUES:
5070: for (p = 0; p < numPoints; p++) {
5071: const PetscInt point = points[2*p];
5072: const PetscInt *perm = perms ? perms[p] : NULL;
5073: const PetscScalar *flip = flips ? flips[p] : NULL;
5074: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5075: } break;
5076: case ADD_ALL_VALUES:
5077: for (p = 0; p < numPoints; p++) {
5078: const PetscInt point = points[2*p];
5079: const PetscInt *perm = perms ? perms[p] : NULL;
5080: const PetscScalar *flip = flips ? flips[p] : NULL;
5081: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5082: } break;
5083: default:
5084: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5085: }
5086: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5087: }
5088: /* Cleanup points */
5089: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5090: /* Cleanup array */
5091: VecRestoreArray(v, &array);
5092: return(0);
5093: }
5095: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
5096: {
5097: PetscMPIInt rank;
5098: PetscInt i, j;
5102: MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
5103: PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
5104: for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
5105: for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
5106: numCIndices = numCIndices ? numCIndices : numRIndices;
5107: for (i = 0; i < numRIndices; i++) {
5108: PetscViewerASCIIPrintf(viewer, "[%d]", rank);
5109: for (j = 0; j < numCIndices; j++) {
5110: #if defined(PETSC_USE_COMPLEX)
5111: PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
5112: #else
5113: PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
5114: #endif
5115: }
5116: PetscViewerASCIIPrintf(viewer, "\n");
5117: }
5118: return(0);
5119: }
5121: /*
5122: DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
5124: Input Parameters:
5125: + section - The section for this data layout
5126: . point - The point contributing dofs with these indices
5127: . off - The global offset of this point
5128: . loff - The local offset of each field
5129: . setBC - The flag determining whether to include indices of bounsary values
5130: . perm - A permutation of the dofs on this point, or NULL
5131: - indperm - A permutation of the entire indices array, or NULL
5133: Output Parameter:
5134: . indices - Indices for dofs on this point
5136: Level: developer
5138: Note: The indices could be local or global, depending on the value of 'off'.
5139: */
5140: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
5141: {
5142: PetscInt dof; /* The number of unknowns on this point */
5143: PetscInt cdof; /* The number of constraints on this point */
5144: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5145: PetscInt cind = 0, k;
5146: PetscErrorCode ierr;
5149: PetscSectionGetDof(section, point, &dof);
5150: PetscSectionGetConstraintDof(section, point, &cdof);
5151: if (!cdof || setBC) {
5152: for (k = 0; k < dof; ++k) {
5153: const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5154: const PetscInt ind = indperm ? indperm[preind] : preind;
5156: indices[ind] = off + k;
5157: }
5158: } else {
5159: PetscSectionGetConstraintIndices(section, point, &cdofs);
5160: for (k = 0; k < dof; ++k) {
5161: const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5162: const PetscInt ind = indperm ? indperm[preind] : preind;
5164: if ((cind < cdof) && (k == cdofs[cind])) {
5165: /* Insert check for returning constrained indices */
5166: indices[ind] = -(off+k+1);
5167: ++cind;
5168: } else {
5169: indices[ind] = off+k-cind;
5170: }
5171: }
5172: }
5173: *loff += dof;
5174: return(0);
5175: }
5177: /*
5178: This version only believes the point offset from the globalSection
5180: . off - The global offset of this point
5181: */
5182: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5183: {
5184: PetscInt numFields, foff, f;
5188: PetscSectionGetNumFields(section, &numFields);
5189: for (f = 0, foff = 0; f < numFields; ++f) {
5190: PetscInt fdof, cfdof;
5191: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5192: PetscInt cind = 0, b;
5193: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5195: PetscSectionGetFieldDof(section, point, f, &fdof);
5196: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5197: if (!cfdof || setBC) {
5198: for (b = 0; b < fdof; ++b) {
5199: const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5200: const PetscInt ind = indperm ? indperm[preind] : preind;
5202: indices[ind] = off+foff+b;
5203: }
5204: } else {
5205: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5206: for (b = 0; b < fdof; ++b) {
5207: const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5208: const PetscInt ind = indperm ? indperm[preind] : preind;
5210: if ((cind < cfdof) && (b == fcdofs[cind])) {
5211: indices[ind] = -(off+foff+b+1);
5212: ++cind;
5213: } else {
5214: indices[ind] = off+foff+b-cind;
5215: }
5216: }
5217: }
5218: foff += (setBC ? fdof : (fdof - cfdof));
5219: foffs[f] += fdof;
5220: }
5221: return(0);
5222: }
5224: /*
5225: This version believes the globalSection offsets for each field, rather than just the point offset
5227: . foffs - The offset into 'indices' for each field, since it is segregated by field
5228: */
5229: PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5230: {
5231: PetscInt numFields, foff, f;
5235: PetscSectionGetNumFields(section, &numFields);
5236: for (f = 0; f < numFields; ++f) {
5237: PetscInt fdof, cfdof;
5238: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5239: PetscInt cind = 0, b;
5240: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5242: PetscSectionGetFieldDof(section, point, f, &fdof);
5243: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5244: PetscSectionGetFieldOffset(globalSection, point, f, &foff);
5245: if (!cfdof || setBC) {
5246: for (b = 0; b < fdof; ++b) {
5247: const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5248: const PetscInt ind = indperm ? indperm[preind] : preind;
5250: indices[ind] = foff+b;
5251: }
5252: } else {
5253: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5254: for (b = 0; b < fdof; ++b) {
5255: const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5256: const PetscInt ind = indperm ? indperm[preind] : preind;
5258: if ((cind < cfdof) && (b == fcdofs[cind])) {
5259: indices[ind] = -(foff+b+1);
5260: ++cind;
5261: } else {
5262: indices[ind] = foff+b-cind;
5263: }
5264: }
5265: }
5266: foffs[f] += fdof;
5267: }
5268: return(0);
5269: }
5271: 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)
5272: {
5273: Mat cMat;
5274: PetscSection aSec, cSec;
5275: IS aIS;
5276: PetscInt aStart = -1, aEnd = -1;
5277: const PetscInt *anchors;
5278: PetscInt numFields, f, p, q, newP = 0;
5279: PetscInt newNumPoints = 0, newNumIndices = 0;
5280: PetscInt *newPoints, *indices, *newIndices;
5281: PetscInt maxAnchor, maxDof;
5282: PetscInt newOffsets[32];
5283: PetscInt *pointMatOffsets[32];
5284: PetscInt *newPointOffsets[32];
5285: PetscScalar *pointMat[32];
5286: PetscScalar *newValues=NULL,*tmpValues;
5287: PetscBool anyConstrained = PETSC_FALSE;
5288: PetscErrorCode ierr;
5293: PetscSectionGetNumFields(section, &numFields);
5295: DMPlexGetAnchors(dm,&aSec,&aIS);
5296: /* if there are point-to-point constraints */
5297: if (aSec) {
5298: PetscArrayzero(newOffsets, 32);
5299: ISGetIndices(aIS,&anchors);
5300: PetscSectionGetChart(aSec,&aStart,&aEnd);
5301: /* figure out how many points are going to be in the new element matrix
5302: * (we allow double counting, because it's all just going to be summed
5303: * into the global matrix anyway) */
5304: for (p = 0; p < 2*numPoints; p+=2) {
5305: PetscInt b = points[p];
5306: PetscInt bDof = 0, bSecDof;
5308: PetscSectionGetDof(section,b,&bSecDof);
5309: if (!bSecDof) {
5310: continue;
5311: }
5312: if (b >= aStart && b < aEnd) {
5313: PetscSectionGetDof(aSec,b,&bDof);
5314: }
5315: if (bDof) {
5316: /* this point is constrained */
5317: /* it is going to be replaced by its anchors */
5318: PetscInt bOff, q;
5320: anyConstrained = PETSC_TRUE;
5321: newNumPoints += bDof;
5322: PetscSectionGetOffset(aSec,b,&bOff);
5323: for (q = 0; q < bDof; q++) {
5324: PetscInt a = anchors[bOff + q];
5325: PetscInt aDof;
5327: PetscSectionGetDof(section,a,&aDof);
5328: newNumIndices += aDof;
5329: for (f = 0; f < numFields; ++f) {
5330: PetscInt fDof;
5332: PetscSectionGetFieldDof(section, a, f, &fDof);
5333: newOffsets[f+1] += fDof;
5334: }
5335: }
5336: }
5337: else {
5338: /* this point is not constrained */
5339: newNumPoints++;
5340: newNumIndices += bSecDof;
5341: for (f = 0; f < numFields; ++f) {
5342: PetscInt fDof;
5344: PetscSectionGetFieldDof(section, b, f, &fDof);
5345: newOffsets[f+1] += fDof;
5346: }
5347: }
5348: }
5349: }
5350: if (!anyConstrained) {
5351: if (outNumPoints) *outNumPoints = 0;
5352: if (outNumIndices) *outNumIndices = 0;
5353: if (outPoints) *outPoints = NULL;
5354: if (outValues) *outValues = NULL;
5355: if (aSec) {ISRestoreIndices(aIS,&anchors);}
5356: return(0);
5357: }
5359: if (outNumPoints) *outNumPoints = newNumPoints;
5360: if (outNumIndices) *outNumIndices = newNumIndices;
5362: for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
5364: if (!outPoints && !outValues) {
5365: if (offsets) {
5366: for (f = 0; f <= numFields; f++) {
5367: offsets[f] = newOffsets[f];
5368: }
5369: }
5370: if (aSec) {ISRestoreIndices(aIS,&anchors);}
5371: return(0);
5372: }
5374: if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
5376: DMGetDefaultConstraints(dm, &cSec, &cMat);
5378: /* workspaces */
5379: if (numFields) {
5380: for (f = 0; f < numFields; f++) {
5381: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5382: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5383: }
5384: }
5385: else {
5386: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5387: DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5388: }
5390: /* get workspaces for the point-to-point matrices */
5391: if (numFields) {
5392: PetscInt totalOffset, totalMatOffset;
5394: for (p = 0; p < numPoints; p++) {
5395: PetscInt b = points[2*p];
5396: PetscInt bDof = 0, bSecDof;
5398: PetscSectionGetDof(section,b,&bSecDof);
5399: if (!bSecDof) {
5400: for (f = 0; f < numFields; f++) {
5401: newPointOffsets[f][p + 1] = 0;
5402: pointMatOffsets[f][p + 1] = 0;
5403: }
5404: continue;
5405: }
5406: if (b >= aStart && b < aEnd) {
5407: PetscSectionGetDof(aSec, b, &bDof);
5408: }
5409: if (bDof) {
5410: for (f = 0; f < numFields; f++) {
5411: PetscInt fDof, q, bOff, allFDof = 0;
5413: PetscSectionGetFieldDof(section, b, f, &fDof);
5414: PetscSectionGetOffset(aSec, b, &bOff);
5415: for (q = 0; q < bDof; q++) {
5416: PetscInt a = anchors[bOff + q];
5417: PetscInt aFDof;
5419: PetscSectionGetFieldDof(section, a, f, &aFDof);
5420: allFDof += aFDof;
5421: }
5422: newPointOffsets[f][p+1] = allFDof;
5423: pointMatOffsets[f][p+1] = fDof * allFDof;
5424: }
5425: }
5426: else {
5427: for (f = 0; f < numFields; f++) {
5428: PetscInt fDof;
5430: PetscSectionGetFieldDof(section, b, f, &fDof);
5431: newPointOffsets[f][p+1] = fDof;
5432: pointMatOffsets[f][p+1] = 0;
5433: }
5434: }
5435: }
5436: for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5437: newPointOffsets[f][0] = totalOffset;
5438: pointMatOffsets[f][0] = totalMatOffset;
5439: for (p = 0; p < numPoints; p++) {
5440: newPointOffsets[f][p+1] += newPointOffsets[f][p];
5441: pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5442: }
5443: totalOffset = newPointOffsets[f][numPoints];
5444: totalMatOffset = pointMatOffsets[f][numPoints];
5445: DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5446: }
5447: }
5448: else {
5449: for (p = 0; p < numPoints; p++) {
5450: PetscInt b = points[2*p];
5451: PetscInt bDof = 0, bSecDof;
5453: PetscSectionGetDof(section,b,&bSecDof);
5454: if (!bSecDof) {
5455: newPointOffsets[0][p + 1] = 0;
5456: pointMatOffsets[0][p + 1] = 0;
5457: continue;
5458: }
5459: if (b >= aStart && b < aEnd) {
5460: PetscSectionGetDof(aSec, b, &bDof);
5461: }
5462: if (bDof) {
5463: PetscInt bOff, q, allDof = 0;
5465: PetscSectionGetOffset(aSec, b, &bOff);
5466: for (q = 0; q < bDof; q++) {
5467: PetscInt a = anchors[bOff + q], aDof;
5469: PetscSectionGetDof(section, a, &aDof);
5470: allDof += aDof;
5471: }
5472: newPointOffsets[0][p+1] = allDof;
5473: pointMatOffsets[0][p+1] = bSecDof * allDof;
5474: }
5475: else {
5476: newPointOffsets[0][p+1] = bSecDof;
5477: pointMatOffsets[0][p+1] = 0;
5478: }
5479: }
5480: newPointOffsets[0][0] = 0;
5481: pointMatOffsets[0][0] = 0;
5482: for (p = 0; p < numPoints; p++) {
5483: newPointOffsets[0][p+1] += newPointOffsets[0][p];
5484: pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5485: }
5486: DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5487: }
5489: /* output arrays */
5490: DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5492: /* get the point-to-point matrices; construct newPoints */
5493: PetscSectionGetMaxDof(aSec, &maxAnchor);
5494: PetscSectionGetMaxDof(section, &maxDof);
5495: DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5496: DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5497: if (numFields) {
5498: for (p = 0, newP = 0; p < numPoints; p++) {
5499: PetscInt b = points[2*p];
5500: PetscInt o = points[2*p+1];
5501: PetscInt bDof = 0, bSecDof;
5503: PetscSectionGetDof(section, b, &bSecDof);
5504: if (!bSecDof) {
5505: continue;
5506: }
5507: if (b >= aStart && b < aEnd) {
5508: PetscSectionGetDof(aSec, b, &bDof);
5509: }
5510: if (bDof) {
5511: PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5513: fStart[0] = 0;
5514: fEnd[0] = 0;
5515: for (f = 0; f < numFields; f++) {
5516: PetscInt fDof;
5518: PetscSectionGetFieldDof(cSec, b, f, &fDof);
5519: fStart[f+1] = fStart[f] + fDof;
5520: fEnd[f+1] = fStart[f+1];
5521: }
5522: PetscSectionGetOffset(cSec, b, &bOff);
5523: DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);
5525: fAnchorStart[0] = 0;
5526: fAnchorEnd[0] = 0;
5527: for (f = 0; f < numFields; f++) {
5528: PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5530: fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5531: fAnchorEnd[f+1] = fAnchorStart[f + 1];
5532: }
5533: PetscSectionGetOffset(aSec, b, &bOff);
5534: for (q = 0; q < bDof; q++) {
5535: PetscInt a = anchors[bOff + q], aOff;
5537: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5538: newPoints[2*(newP + q)] = a;
5539: newPoints[2*(newP + q) + 1] = 0;
5540: PetscSectionGetOffset(section, a, &aOff);
5541: DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);
5542: }
5543: newP += bDof;
5545: if (outValues) {
5546: /* get the point-to-point submatrix */
5547: for (f = 0; f < numFields; f++) {
5548: MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5549: }
5550: }
5551: }
5552: else {
5553: newPoints[2 * newP] = b;
5554: newPoints[2 * newP + 1] = o;
5555: newP++;
5556: }
5557: }
5558: } else {
5559: for (p = 0; p < numPoints; p++) {
5560: PetscInt b = points[2*p];
5561: PetscInt o = points[2*p+1];
5562: PetscInt bDof = 0, bSecDof;
5564: PetscSectionGetDof(section, b, &bSecDof);
5565: if (!bSecDof) {
5566: continue;
5567: }
5568: if (b >= aStart && b < aEnd) {
5569: PetscSectionGetDof(aSec, b, &bDof);
5570: }
5571: if (bDof) {
5572: PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5574: PetscSectionGetOffset(cSec, b, &bOff);
5575: DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);
5577: PetscSectionGetOffset (aSec, b, &bOff);
5578: for (q = 0; q < bDof; q++) {
5579: PetscInt a = anchors[bOff + q], aOff;
5581: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5583: newPoints[2*(newP + q)] = a;
5584: newPoints[2*(newP + q) + 1] = 0;
5585: PetscSectionGetOffset(section, a, &aOff);
5586: DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);
5587: }
5588: newP += bDof;
5590: /* get the point-to-point submatrix */
5591: if (outValues) {
5592: MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5593: }
5594: }
5595: else {
5596: newPoints[2 * newP] = b;
5597: newPoints[2 * newP + 1] = o;
5598: newP++;
5599: }
5600: }
5601: }
5603: if (outValues) {
5604: DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5605: PetscArrayzero(tmpValues,newNumIndices*numIndices);
5606: /* multiply constraints on the right */
5607: if (numFields) {
5608: for (f = 0; f < numFields; f++) {
5609: PetscInt oldOff = offsets[f];
5611: for (p = 0; p < numPoints; p++) {
5612: PetscInt cStart = newPointOffsets[f][p];
5613: PetscInt b = points[2 * p];
5614: PetscInt c, r, k;
5615: PetscInt dof;
5617: PetscSectionGetFieldDof(section,b,f,&dof);
5618: if (!dof) {
5619: continue;
5620: }
5621: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5622: PetscInt nCols = newPointOffsets[f][p+1]-cStart;
5623: const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5625: for (r = 0; r < numIndices; r++) {
5626: for (c = 0; c < nCols; c++) {
5627: for (k = 0; k < dof; k++) {
5628: tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5629: }
5630: }
5631: }
5632: }
5633: else {
5634: /* copy this column as is */
5635: for (r = 0; r < numIndices; r++) {
5636: for (c = 0; c < dof; c++) {
5637: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5638: }
5639: }
5640: }
5641: oldOff += dof;
5642: }
5643: }
5644: }
5645: else {
5646: PetscInt oldOff = 0;
5647: for (p = 0; p < numPoints; p++) {
5648: PetscInt cStart = newPointOffsets[0][p];
5649: PetscInt b = points[2 * p];
5650: PetscInt c, r, k;
5651: PetscInt dof;
5653: PetscSectionGetDof(section,b,&dof);
5654: if (!dof) {
5655: continue;
5656: }
5657: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5658: PetscInt nCols = newPointOffsets[0][p+1]-cStart;
5659: const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5661: for (r = 0; r < numIndices; r++) {
5662: for (c = 0; c < nCols; c++) {
5663: for (k = 0; k < dof; k++) {
5664: tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5665: }
5666: }
5667: }
5668: }
5669: else {
5670: /* copy this column as is */
5671: for (r = 0; r < numIndices; r++) {
5672: for (c = 0; c < dof; c++) {
5673: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5674: }
5675: }
5676: }
5677: oldOff += dof;
5678: }
5679: }
5681: if (multiplyLeft) {
5682: DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5683: PetscArrayzero(newValues,newNumIndices*newNumIndices);
5684: /* multiply constraints transpose on the left */
5685: if (numFields) {
5686: for (f = 0; f < numFields; f++) {
5687: PetscInt oldOff = offsets[f];
5689: for (p = 0; p < numPoints; p++) {
5690: PetscInt rStart = newPointOffsets[f][p];
5691: PetscInt b = points[2 * p];
5692: PetscInt c, r, k;
5693: PetscInt dof;
5695: PetscSectionGetFieldDof(section,b,f,&dof);
5696: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5697: PetscInt nRows = newPointOffsets[f][p+1]-rStart;
5698: const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5700: for (r = 0; r < nRows; r++) {
5701: for (c = 0; c < newNumIndices; c++) {
5702: for (k = 0; k < dof; k++) {
5703: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5704: }
5705: }
5706: }
5707: }
5708: else {
5709: /* copy this row as is */
5710: for (r = 0; r < dof; r++) {
5711: for (c = 0; c < newNumIndices; c++) {
5712: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5713: }
5714: }
5715: }
5716: oldOff += dof;
5717: }
5718: }
5719: }
5720: else {
5721: PetscInt oldOff = 0;
5723: for (p = 0; p < numPoints; p++) {
5724: PetscInt rStart = newPointOffsets[0][p];
5725: PetscInt b = points[2 * p];
5726: PetscInt c, r, k;
5727: PetscInt dof;
5729: PetscSectionGetDof(section,b,&dof);
5730: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5731: PetscInt nRows = newPointOffsets[0][p+1]-rStart;
5732: const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5734: for (r = 0; r < nRows; r++) {
5735: for (c = 0; c < newNumIndices; c++) {
5736: for (k = 0; k < dof; k++) {
5737: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5738: }
5739: }
5740: }
5741: }
5742: else {
5743: /* copy this row as is */
5744: for (r = 0; r < dof; r++) {
5745: for (c = 0; c < newNumIndices; c++) {
5746: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5747: }
5748: }
5749: }
5750: oldOff += dof;
5751: }
5752: }
5754: DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5755: }
5756: else {
5757: newValues = tmpValues;
5758: }
5759: }
5761: /* clean up */
5762: DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5763: DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5765: if (numFields) {
5766: for (f = 0; f < numFields; f++) {
5767: DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5768: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5769: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5770: }
5771: }
5772: else {
5773: DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5774: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5775: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5776: }
5777: ISRestoreIndices(aIS,&anchors);
5779: /* output */
5780: if (outPoints) {
5781: *outPoints = newPoints;
5782: }
5783: else {
5784: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5785: }
5786: if (outValues) {
5787: *outValues = newValues;
5788: }
5789: for (f = 0; f <= numFields; f++) {
5790: offsets[f] = newOffsets[f];
5791: }
5792: return(0);
5793: }
5795: /*@C
5796: DMPlexGetClosureIndices - Get the global indices for all local points in the closure of the given point
5798: Not collective
5800: Input Parameters:
5801: + dm - The DM
5802: . section - The section describing the local layout
5803: . globalSection - The section describing the parallel layout
5804: - point - The mesh point
5806: Output parameters:
5807: + numIndices - The number of indices
5808: . indices - The indices
5809: - outOffsets - Field offset if not NULL
5811: Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5813: Level: advanced
5815: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5816: @*/
5817: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5818: {
5819: PetscSection clSection;
5820: IS clPoints;
5821: const PetscInt *clp, *clperm;
5822: const PetscInt **perms[32] = {NULL};
5823: PetscInt *points = NULL, *pointsNew;
5824: PetscInt numPoints, numPointsNew;
5825: PetscInt offsets[32];
5826: PetscInt Nf, Nind, NindNew, off, globalOff, f, p;
5827: PetscErrorCode ierr;
5835: PetscSectionGetNumFields(section, &Nf);
5836: if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5837: PetscArrayzero(offsets, 32);
5838: /* Get points in closure */
5839: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5840: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5841: /* Get number of indices and indices per field */
5842: for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5843: PetscInt dof, fdof;
5845: PetscSectionGetDof(section, points[p], &dof);
5846: for (f = 0; f < Nf; ++f) {
5847: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5848: offsets[f+1] += fdof;
5849: }
5850: Nind += dof;
5851: }
5852: for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5853: if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5854: if (!Nf) offsets[1] = Nind;
5855: /* Get dual space symmetries */
5856: for (f = 0; f < PetscMax(1,Nf); f++) {
5857: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5858: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5859: }
5860: /* Correct for hanging node constraints */
5861: {
5862: DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5863: if (numPointsNew) {
5864: for (f = 0; f < PetscMax(1,Nf); f++) {
5865: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5866: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5867: }
5868: for (f = 0; f < PetscMax(1,Nf); f++) {
5869: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5870: else {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5871: }
5872: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5873: numPoints = numPointsNew;
5874: Nind = NindNew;
5875: points = pointsNew;
5876: }
5877: }
5878: /* Calculate indices */
5879: DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5880: if (Nf) {
5881: if (outOffsets) {
5882: PetscInt f;
5884: for (f = 0; f <= Nf; f++) {
5885: outOffsets[f] = offsets[f];
5886: }
5887: }
5888: for (p = 0; p < numPoints; p++) {
5889: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5890: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);
5891: }
5892: } else {
5893: for (p = 0, off = 0; p < numPoints; p++) {
5894: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5896: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5897: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);
5898: }
5899: }
5900: /* Cleanup points */
5901: for (f = 0; f < PetscMax(1,Nf); f++) {
5902: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5903: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5904: }
5905: if (numPointsNew) {
5906: DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5907: } else {
5908: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5909: }
5910: if (numIndices) *numIndices = Nind;
5911: return(0);
5912: }
5914: /*@C
5915: DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5917: Not collective
5919: Input Parameters:
5920: + dm - The DM
5921: . section - The section describing the layout in v, or NULL to use the default section
5922: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5923: . point - The mesh point
5924: . numIndices - The number of indices
5925: . indices - The indices
5926: - outOffsets - Field offset if not NULL
5928: Level: advanced
5930: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5931: @*/
5932: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5933: {
5939: DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5940: return(0);
5941: }
5943: /*@C
5944: DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5946: Not collective
5948: Input Parameters:
5949: + dm - The DM
5950: . section - The section describing the layout in v, or NULL to use the default section
5951: . globalSection - The section describing the layout in v, or NULL to use the default global section
5952: . A - The matrix
5953: . point - The point in the DM
5954: . values - The array of values
5955: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5957: Fortran Notes:
5958: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5960: Level: intermediate
5962: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5963: @*/
5964: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5965: {
5966: DM_Plex *mesh = (DM_Plex*) dm->data;
5967: PetscSection clSection;
5968: IS clPoints;
5969: PetscInt *points = NULL, *newPoints;
5970: const PetscInt *clp, *clperm;
5971: PetscInt *indices;
5972: PetscInt offsets[32];
5973: const PetscInt **perms[32] = {NULL};
5974: const PetscScalar **flips[32] = {NULL};
5975: PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5976: PetscScalar *valCopy = NULL;
5977: PetscScalar *newValues;
5978: PetscErrorCode ierr;
5982: if (!section) {DMGetLocalSection(dm, §ion);}
5984: if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5987: PetscSectionGetNumFields(section, &numFields);
5988: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5989: PetscArrayzero(offsets, 32);
5990: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5991: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5992: for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5993: PetscInt fdof;
5995: PetscSectionGetDof(section, points[p], &dof);
5996: for (f = 0; f < numFields; ++f) {
5997: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5998: offsets[f+1] += fdof;
5999: }
6000: numIndices += dof;
6001: }
6002: for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6004: if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
6005: /* Get symmetries */
6006: for (f = 0; f < PetscMax(1,numFields); f++) {
6007: if (numFields) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6008: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6009: if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
6010: PetscInt foffset = offsets[f];
6012: for (p = 0; p < numPoints; p++) {
6013: PetscInt point = points[2*p], fdof;
6014: const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
6016: if (!numFields) {
6017: PetscSectionGetDof(section,point,&fdof);
6018: } else {
6019: PetscSectionGetFieldDof(section,point,f,&fdof);
6020: }
6021: if (flip) {
6022: PetscInt i, j, k;
6024: if (!valCopy) {
6025: DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6026: for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
6027: values = valCopy;
6028: }
6029: for (i = 0; i < fdof; i++) {
6030: PetscScalar fval = flip[i];
6032: for (k = 0; k < numIndices; k++) {
6033: valCopy[numIndices * (foffset + i) + k] *= fval;
6034: valCopy[numIndices * k + (foffset + i)] *= fval;
6035: }
6036: }
6037: }
6038: foffset += fdof;
6039: }
6040: }
6041: }
6042: DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
6043: if (newNumPoints) {
6044: if (valCopy) {
6045: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6046: }
6047: for (f = 0; f < PetscMax(1,numFields); f++) {
6048: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6049: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6050: }
6051: for (f = 0; f < PetscMax(1,numFields); f++) {
6052: if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
6053: else {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
6054: }
6055: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6056: numPoints = newNumPoints;
6057: numIndices = newNumIndices;
6058: points = newPoints;
6059: values = newValues;
6060: }
6061: DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
6062: if (numFields) {
6063: PetscBool useFieldOffsets;
6065: PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
6066: if (useFieldOffsets) {
6067: for (p = 0; p < numPoints; p++) {
6068: DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices);
6069: }
6070: } else {
6071: for (p = 0; p < numPoints; p++) {
6072: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6073: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);
6074: }
6075: }
6076: } else {
6077: for (p = 0, off = 0; p < numPoints; p++) {
6078: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
6079: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6080: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);
6081: }
6082: }
6083: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
6084: MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6085: if (mesh->printFEM > 1) {
6086: PetscInt i;
6087: PetscPrintf(PETSC_COMM_SELF, " Indices:");
6088: for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
6089: PetscPrintf(PETSC_COMM_SELF, "\n");
6090: }
6091: if (ierr) {
6092: PetscMPIInt rank;
6093: PetscErrorCode ierr2;
6095: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6096: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6097: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
6098: ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
6099:
6100: }
6101: for (f = 0; f < PetscMax(1,numFields); f++) {
6102: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6103: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6104: }
6105: if (newNumPoints) {
6106: DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
6107: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
6108: }
6109: else {
6110: if (valCopy) {
6111: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6112: }
6113: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6114: }
6115: DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
6116: return(0);
6117: }
6119: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6120: {
6121: DM_Plex *mesh = (DM_Plex*) dmf->data;
6122: PetscInt *fpoints = NULL, *ftotpoints = NULL;
6123: PetscInt *cpoints = NULL;
6124: PetscInt *findices, *cindices;
6125: const PetscInt *fclperm, *cclperm;
6126: PetscInt foffsets[32], coffsets[32];
6127: CellRefiner cellRefiner;
6128: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6129: PetscErrorCode ierr;
6134: if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6136: if (!csection) {DMGetLocalSection(dmc, &csection);}
6138: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6140: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6143: PetscSectionGetNumFields(fsection, &numFields);
6144: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6145: PetscArrayzero(foffsets, 32);
6146: PetscArrayzero(coffsets, 32);
6147: PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6148: PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6149: /* Column indices */
6150: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6151: maxFPoints = numCPoints;
6152: /* Compress out points not in the section */
6153: /* TODO: Squeeze out points with 0 dof as well */
6154: PetscSectionGetChart(csection, &pStart, &pEnd);
6155: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6156: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6157: cpoints[q*2] = cpoints[p];
6158: cpoints[q*2+1] = cpoints[p+1];
6159: ++q;
6160: }
6161: }
6162: numCPoints = q;
6163: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6164: PetscInt fdof;
6166: PetscSectionGetDof(csection, cpoints[p], &dof);
6167: if (!dof) continue;
6168: for (f = 0; f < numFields; ++f) {
6169: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6170: coffsets[f+1] += fdof;
6171: }
6172: numCIndices += dof;
6173: }
6174: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6175: /* Row indices */
6176: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6177: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6178: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6179: for (r = 0, q = 0; r < numSubcells; ++r) {
6180: /* TODO Map from coarse to fine cells */
6181: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6182: /* Compress out points not in the section */
6183: PetscSectionGetChart(fsection, &pStart, &pEnd);
6184: for (p = 0; p < numFPoints*2; p += 2) {
6185: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6186: PetscSectionGetDof(fsection, fpoints[p], &dof);
6187: if (!dof) continue;
6188: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6189: if (s < q) continue;
6190: ftotpoints[q*2] = fpoints[p];
6191: ftotpoints[q*2+1] = fpoints[p+1];
6192: ++q;
6193: }
6194: }
6195: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6196: }
6197: numFPoints = q;
6198: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6199: PetscInt fdof;
6201: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6202: if (!dof) continue;
6203: for (f = 0; f < numFields; ++f) {
6204: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6205: foffsets[f+1] += fdof;
6206: }
6207: numFIndices += dof;
6208: }
6209: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6211: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6212: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6213: DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6214: DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6215: if (numFields) {
6216: const PetscInt **permsF[32] = {NULL};
6217: const PetscInt **permsC[32] = {NULL};
6219: for (f = 0; f < numFields; f++) {
6220: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6221: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6222: }
6223: for (p = 0; p < numFPoints; p++) {
6224: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6225: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6226: }
6227: for (p = 0; p < numCPoints; p++) {
6228: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6229: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6230: }
6231: for (f = 0; f < numFields; f++) {
6232: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6233: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6234: }
6235: } else {
6236: const PetscInt **permsF = NULL;
6237: const PetscInt **permsC = NULL;
6239: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6240: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6241: for (p = 0, off = 0; p < numFPoints; p++) {
6242: const PetscInt *perm = permsF ? permsF[p] : NULL;
6244: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6245: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6246: }
6247: for (p = 0, off = 0; p < numCPoints; p++) {
6248: const PetscInt *perm = permsC ? permsC[p] : NULL;
6250: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6251: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6252: }
6253: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6254: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6255: }
6256: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
6257: /* TODO: flips */
6258: MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6259: if (ierr) {
6260: PetscMPIInt rank;
6261: PetscErrorCode ierr2;
6263: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6264: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6265: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6266: ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6267: ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6268:
6269: }
6270: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6271: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6272: DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6273: DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6274: return(0);
6275: }
6277: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6278: {
6279: PetscInt *fpoints = NULL, *ftotpoints = NULL;
6280: PetscInt *cpoints = NULL;
6281: PetscInt foffsets[32], coffsets[32];
6282: const PetscInt *fclperm, *cclperm;
6283: CellRefiner cellRefiner;
6284: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6290: if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6292: if (!csection) {DMGetLocalSection(dmc, &csection);}
6294: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6296: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6298: PetscSectionGetNumFields(fsection, &numFields);
6299: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6300: PetscArrayzero(foffsets, 32);
6301: PetscArrayzero(coffsets, 32);
6302: PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6303: PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6304: /* Column indices */
6305: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6306: maxFPoints = numCPoints;
6307: /* Compress out points not in the section */
6308: /* TODO: Squeeze out points with 0 dof as well */
6309: PetscSectionGetChart(csection, &pStart, &pEnd);
6310: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6311: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6312: cpoints[q*2] = cpoints[p];
6313: cpoints[q*2+1] = cpoints[p+1];
6314: ++q;
6315: }
6316: }
6317: numCPoints = q;
6318: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6319: PetscInt fdof;
6321: PetscSectionGetDof(csection, cpoints[p], &dof);
6322: if (!dof) continue;
6323: for (f = 0; f < numFields; ++f) {
6324: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6325: coffsets[f+1] += fdof;
6326: }
6327: numCIndices += dof;
6328: }
6329: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6330: /* Row indices */
6331: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6332: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6333: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6334: for (r = 0, q = 0; r < numSubcells; ++r) {
6335: /* TODO Map from coarse to fine cells */
6336: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6337: /* Compress out points not in the section */
6338: PetscSectionGetChart(fsection, &pStart, &pEnd);
6339: for (p = 0; p < numFPoints*2; p += 2) {
6340: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6341: PetscSectionGetDof(fsection, fpoints[p], &dof);
6342: if (!dof) continue;
6343: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6344: if (s < q) continue;
6345: ftotpoints[q*2] = fpoints[p];
6346: ftotpoints[q*2+1] = fpoints[p+1];
6347: ++q;
6348: }
6349: }
6350: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6351: }
6352: numFPoints = q;
6353: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6354: PetscInt fdof;
6356: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6357: if (!dof) continue;
6358: for (f = 0; f < numFields; ++f) {
6359: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6360: foffsets[f+1] += fdof;
6361: }
6362: numFIndices += dof;
6363: }
6364: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6366: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6367: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6368: if (numFields) {
6369: const PetscInt **permsF[32] = {NULL};
6370: const PetscInt **permsC[32] = {NULL};
6372: for (f = 0; f < numFields; f++) {
6373: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6374: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6375: }
6376: for (p = 0; p < numFPoints; p++) {
6377: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6378: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6379: }
6380: for (p = 0; p < numCPoints; p++) {
6381: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6382: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6383: }
6384: for (f = 0; f < numFields; f++) {
6385: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6386: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6387: }
6388: } else {
6389: const PetscInt **permsF = NULL;
6390: const PetscInt **permsC = NULL;
6392: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6393: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6394: for (p = 0, off = 0; p < numFPoints; p++) {
6395: const PetscInt *perm = permsF ? permsF[p] : NULL;
6397: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6398: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6399: }
6400: for (p = 0, off = 0; p < numCPoints; p++) {
6401: const PetscInt *perm = permsC ? permsC[p] : NULL;
6403: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6404: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6405: }
6406: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6407: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6408: }
6409: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6410: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6411: return(0);
6412: }
6414: /*@
6415: DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6417: Input Parameter:
6418: . dm - The DMPlex object
6420: Output Parameters:
6421: + cMax - The first hybrid cell
6422: . fMax - The first hybrid face
6423: . eMax - The first hybrid edge
6424: - vMax - The first hybrid vertex
6426: Level: developer
6428: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6429: @*/
6430: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6431: {
6432: DM_Plex *mesh = (DM_Plex*) dm->data;
6433: PetscInt dim;
6438: DMGetDimension(dm, &dim);
6439: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6440: if (cMax) *cMax = mesh->hybridPointMax[dim];
6441: if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6442: if (eMax) *eMax = mesh->hybridPointMax[1];
6443: if (vMax) *vMax = mesh->hybridPointMax[0];
6444: return(0);
6445: }
6447: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6448: {
6449: IS is, his;
6450: PetscInt first = 0, stride;
6451: PetscBool isStride;
6455: DMLabelGetStratumIS(depthLabel, d, &is);
6456: PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6457: if (isStride) {
6458: ISStrideGetInfo(is, &first, &stride);
6459: }
6460: if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6461: ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6462: DMLabelSetStratumIS(dimLabel, d, his);
6463: ISDestroy(&his);
6464: ISDestroy(&is);
6465: return(0);
6466: }
6468: /*@
6469: DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6471: Input Parameters:
6472: + dm - The DMPlex object
6473: . cMax - The first hybrid cell
6474: . fMax - The first hybrid face
6475: . eMax - The first hybrid edge
6476: - vMax - The first hybrid vertex
6478: Level: developer
6480: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6481: @*/
6482: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6483: {
6484: DM_Plex *mesh = (DM_Plex*) dm->data;
6485: PetscInt dim;
6490: DMGetDimension(dm, &dim);
6491: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6492: if (cMax >= 0) mesh->hybridPointMax[dim] = cMax;
6493: if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6494: if (eMax >= 0) mesh->hybridPointMax[1] = eMax;
6495: if (vMax >= 0) mesh->hybridPointMax[0] = vMax;
6496: return(0);
6497: }
6499: /*@C
6500: DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6502: Input Parameter:
6503: . dm - The DMPlex object
6505: Output Parameter:
6506: . cellHeight - The height of a cell
6508: Level: developer
6510: .seealso DMPlexSetVTKCellHeight()
6511: @*/
6512: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6513: {
6514: DM_Plex *mesh = (DM_Plex*) dm->data;
6519: *cellHeight = mesh->vtkCellHeight;
6520: return(0);
6521: }
6523: /*@C
6524: DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6526: Input Parameters:
6527: + dm - The DMPlex object
6528: - cellHeight - The height of a cell
6530: Level: developer
6532: .seealso DMPlexGetVTKCellHeight()
6533: @*/
6534: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6535: {
6536: DM_Plex *mesh = (DM_Plex*) dm->data;
6540: mesh->vtkCellHeight = cellHeight;
6541: return(0);
6542: }
6544: /* We can easily have a form that takes an IS instead */
6545: PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6546: {
6547: PetscSection section, globalSection;
6548: PetscInt *numbers, p;
6552: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
6553: PetscSectionSetChart(section, pStart, pEnd);
6554: for (p = pStart; p < pEnd; ++p) {
6555: PetscSectionSetDof(section, p, 1);
6556: }
6557: PetscSectionSetUp(section);
6558: PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6559: PetscMalloc1(pEnd - pStart, &numbers);
6560: for (p = pStart; p < pEnd; ++p) {
6561: PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6562: if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6563: else numbers[p-pStart] += shift;
6564: }
6565: ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6566: if (globalSize) {
6567: PetscLayout layout;
6568: PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6569: PetscLayoutGetSize(layout, globalSize);
6570: PetscLayoutDestroy(&layout);
6571: }
6572: PetscSectionDestroy(§ion);
6573: PetscSectionDestroy(&globalSection);
6574: return(0);
6575: }
6577: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6578: {
6579: PetscInt cellHeight, cStart, cEnd, cMax;
6583: DMPlexGetVTKCellHeight(dm, &cellHeight);
6584: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6585: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6586: if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6587: DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6588: return(0);
6589: }
6591: /*@
6592: DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6594: Input Parameter:
6595: . dm - The DMPlex object
6597: Output Parameter:
6598: . globalCellNumbers - Global cell numbers for all cells on this process
6600: Level: developer
6602: .seealso DMPlexGetVertexNumbering()
6603: @*/
6604: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6605: {
6606: DM_Plex *mesh = (DM_Plex*) dm->data;
6611: if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6612: *globalCellNumbers = mesh->globalCellNumbers;
6613: return(0);
6614: }
6616: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6617: {
6618: PetscInt vStart, vEnd, vMax;
6623: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6624: DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6625: if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6626: DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6627: return(0);
6628: }
6630: /*@
6631: DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
6633: Input Parameter:
6634: . dm - The DMPlex object
6636: Output Parameter:
6637: . globalVertexNumbers - Global vertex numbers for all vertices on this process
6639: Level: developer
6641: .seealso DMPlexGetCellNumbering()
6642: @*/
6643: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6644: {
6645: DM_Plex *mesh = (DM_Plex*) dm->data;
6650: if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6651: *globalVertexNumbers = mesh->globalVertexNumbers;
6652: return(0);
6653: }
6655: /*@
6656: DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6658: Input Parameter:
6659: . dm - The DMPlex object
6661: Output Parameter:
6662: . globalPointNumbers - Global numbers for all points on this process
6664: Level: developer
6666: .seealso DMPlexGetCellNumbering()
6667: @*/
6668: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6669: {
6670: IS nums[4];
6671: PetscInt depths[4], gdepths[4], starts[4];
6672: PetscInt depth, d, shift = 0;
6677: DMPlexGetDepth(dm, &depth);
6678: /* For unstratified meshes use dim instead of depth */
6679: if (depth < 0) {DMGetDimension(dm, &depth);}
6680: for (d = 0; d <= depth; ++d) {
6681: PetscInt end;
6683: depths[d] = depth-d;
6684: DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6685: if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6686: }
6687: PetscSortIntWithArray(depth+1, starts, depths);
6688: MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6689: for (d = 0; d <= depth; ++d) {
6690: if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6691: }
6692: for (d = 0; d <= depth; ++d) {
6693: PetscInt pStart, pEnd, gsize;
6695: DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6696: DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6697: shift += gsize;
6698: }
6699: ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6700: for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6701: return(0);
6702: }
6705: /*@
6706: DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6708: Input Parameter:
6709: . dm - The DMPlex object
6711: Output Parameter:
6712: . ranks - The rank field
6714: Options Database Keys:
6715: . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6717: Level: intermediate
6719: .seealso: DMView()
6720: @*/
6721: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6722: {
6723: DM rdm;
6724: PetscFE fe;
6725: PetscScalar *r;
6726: PetscMPIInt rank;
6727: PetscInt dim, cStart, cEnd, c;
6733: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6734: DMClone(dm, &rdm);
6735: DMGetDimension(rdm, &dim);
6736: PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6737: PetscObjectSetName((PetscObject) fe, "rank");
6738: DMSetField(rdm, 0, NULL, (PetscObject) fe);
6739: PetscFEDestroy(&fe);
6740: DMCreateDS(rdm);
6741: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6742: DMCreateGlobalVector(rdm, ranks);
6743: PetscObjectSetName((PetscObject) *ranks, "partition");
6744: VecGetArray(*ranks, &r);
6745: for (c = cStart; c < cEnd; ++c) {
6746: PetscScalar *lr;
6748: DMPlexPointGlobalRef(rdm, c, r, &lr);
6749: if (lr) *lr = rank;
6750: }
6751: VecRestoreArray(*ranks, &r);
6752: DMDestroy(&rdm);
6753: return(0);
6754: }
6756: /*@
6757: DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
6759: Input Parameters:
6760: + dm - The DMPlex
6761: - label - The DMLabel
6763: Output Parameter:
6764: . val - The label value field
6766: Options Database Keys:
6767: . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
6769: Level: intermediate
6771: .seealso: DMView()
6772: @*/
6773: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6774: {
6775: DM rdm;
6776: PetscFE fe;
6777: PetscScalar *v;
6778: PetscInt dim, cStart, cEnd, c;
6785: DMClone(dm, &rdm);
6786: DMGetDimension(rdm, &dim);
6787: PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6788: PetscObjectSetName((PetscObject) fe, "label_value");
6789: DMSetField(rdm, 0, NULL, (PetscObject) fe);
6790: PetscFEDestroy(&fe);
6791: DMCreateDS(rdm);
6792: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6793: DMCreateGlobalVector(rdm, val);
6794: PetscObjectSetName((PetscObject) *val, "label_value");
6795: VecGetArray(*val, &v);
6796: for (c = cStart; c < cEnd; ++c) {
6797: PetscScalar *lv;
6798: PetscInt cval;
6800: DMPlexPointGlobalRef(rdm, c, v, &lv);
6801: DMLabelGetValue(label, c, &cval);
6802: *lv = cval;
6803: }
6804: VecRestoreArray(*val, &v);
6805: DMDestroy(&rdm);
6806: return(0);
6807: }
6809: /*@
6810: DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6812: Input Parameter:
6813: . dm - The DMPlex object
6815: Note: This is a useful diagnostic when creating meshes programmatically.
6817: Level: developer
6819: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6820: @*/
6821: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6822: {
6823: PetscSection coneSection, supportSection;
6824: const PetscInt *cone, *support;
6825: PetscInt coneSize, c, supportSize, s;
6826: PetscInt pStart, pEnd, p, pp, csize, ssize;
6827: PetscBool storagecheck = PETSC_TRUE;
6828: PetscErrorCode ierr;
6832: DMPlexGetConeSection(dm, &coneSection);
6833: DMPlexGetSupportSection(dm, &supportSection);
6834: /* Check that point p is found in the support of its cone points, and vice versa */
6835: DMPlexGetChart(dm, &pStart, &pEnd);
6836: for (p = pStart; p < pEnd; ++p) {
6837: DMPlexGetConeSize(dm, p, &coneSize);
6838: DMPlexGetCone(dm, p, &cone);
6839: for (c = 0; c < coneSize; ++c) {
6840: PetscBool dup = PETSC_FALSE;
6841: PetscInt d;
6842: for (d = c-1; d >= 0; --d) {
6843: if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6844: }
6845: DMPlexGetSupportSize(dm, cone[c], &supportSize);
6846: DMPlexGetSupport(dm, cone[c], &support);
6847: for (s = 0; s < supportSize; ++s) {
6848: if (support[s] == p) break;
6849: }
6850: if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6851: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6852: for (s = 0; s < coneSize; ++s) {
6853: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6854: }
6855: PetscPrintf(PETSC_COMM_SELF, "\n");
6856: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6857: for (s = 0; s < supportSize; ++s) {
6858: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6859: }
6860: PetscPrintf(PETSC_COMM_SELF, "\n");
6861: if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6862: else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6863: }
6864: }
6865: DMPlexGetTreeParent(dm, p, &pp, NULL);
6866: if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6867: DMPlexGetSupportSize(dm, p, &supportSize);
6868: DMPlexGetSupport(dm, p, &support);
6869: for (s = 0; s < supportSize; ++s) {
6870: DMPlexGetConeSize(dm, support[s], &coneSize);
6871: DMPlexGetCone(dm, support[s], &cone);
6872: for (c = 0; c < coneSize; ++c) {
6873: DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
6874: if (cone[c] != pp) { c = 0; break; }
6875: if (cone[c] == p) break;
6876: }
6877: if (c >= coneSize) {
6878: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6879: for (c = 0; c < supportSize; ++c) {
6880: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6881: }
6882: PetscPrintf(PETSC_COMM_SELF, "\n");
6883: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6884: for (c = 0; c < coneSize; ++c) {
6885: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6886: }
6887: PetscPrintf(PETSC_COMM_SELF, "\n");
6888: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6889: }
6890: }
6891: }
6892: if (storagecheck) {
6893: PetscSectionGetStorageSize(coneSection, &csize);
6894: PetscSectionGetStorageSize(supportSection, &ssize);
6895: if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6896: }
6897: return(0);
6898: }
6900: /*@
6901: DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6903: Input Parameters:
6904: + dm - The DMPlex object
6905: - cellHeight - Normally 0
6907: Note: This is a useful diagnostic when creating meshes programmatically.
6908: Currently applicable only to homogeneous simplex or tensor meshes.
6910: Level: developer
6912: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6913: @*/
6914: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
6915: {
6916: PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6917: PetscBool isSimplex = PETSC_FALSE;
6922: DMGetDimension(dm, &dim);
6923: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6924: if (cStart < cEnd) {
6925: DMPlexGetConeSize(dm, cStart, &c);
6926: isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE;
6927: }
6928: switch (dim) {
6929: case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6930: case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6931: case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6932: default:
6933: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6934: }
6935: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6936: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6937: cMax = cMax >= 0 ? cMax : cEnd;
6938: for (c = cStart; c < cMax; ++c) {
6939: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6941: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6942: for (cl = 0; cl < closureSize*2; cl += 2) {
6943: const PetscInt p = closure[cl];
6944: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6945: }
6946: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6947: if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D", c, coneSize, numCorners);
6948: }
6949: for (c = cMax; c < cEnd; ++c) {
6950: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6952: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6953: for (cl = 0; cl < closureSize*2; cl += 2) {
6954: const PetscInt p = closure[cl];
6955: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6956: }
6957: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6958: if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has %D vertices > %D", c, coneSize, numHybridCorners);
6959: }
6960: return(0);
6961: }
6963: /*@
6964: DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6966: Input Parameters:
6967: + dm - The DMPlex object
6968: - cellHeight - Normally 0
6970: Note: This is a useful diagnostic when creating meshes programmatically.
6972: Level: developer
6974: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6975: @*/
6976: PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
6977: {
6978: PetscInt pMax[4];
6979: PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h;
6984: DMGetDimension(dm, &dim);
6985: DMPlexGetDepth(dm, &depth);
6986: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6987: DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6988: for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
6989: DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6990: for (c = cStart; c < cEnd; ++c) {
6991: const PetscInt *cone, *ornt, *faces;
6992: PetscInt numFaces, faceSize, coneSize,f;
6993: PetscInt *closure = NULL, closureSize, cl, numCorners = 0;
6995: if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6996: DMPlexGetConeSize(dm, c, &coneSize);
6997: DMPlexGetCone(dm, c, &cone);
6998: DMPlexGetConeOrientation(dm, c, &ornt);
6999: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7000: for (cl = 0; cl < closureSize*2; cl += 2) {
7001: const PetscInt p = closure[cl];
7002: if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
7003: }
7004: DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
7005: if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
7006: for (f = 0; f < numFaces; ++f) {
7007: PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
7009: DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
7010: for (cl = 0; cl < fclosureSize*2; cl += 2) {
7011: const PetscInt p = fclosure[cl];
7012: if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
7013: }
7014: 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);
7015: for (v = 0; v < fnumCorners; ++v) {
7016: 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]);
7017: }
7018: DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
7019: }
7020: DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
7021: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7022: }
7023: }
7024: return(0);
7025: }
7027: /*@
7028: DMPlexCheckGeometry - Check the geometry of mesh cells
7030: Input Parameter:
7031: . dm - The DMPlex object
7033: Note: This is a useful diagnostic when creating meshes programmatically.
7035: Level: developer
7037: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
7038: @*/
7039: PetscErrorCode DMPlexCheckGeometry(DM dm)
7040: {
7041: PetscReal detJ, J[9], refVol = 1.0;
7042: PetscReal vol;
7043: PetscInt dim, depth, d, cStart, cEnd, c, cMax;
7047: DMGetDimension(dm, &dim);
7048: DMPlexGetDepth(dm, &depth);
7049: for (d = 0; d < dim; ++d) refVol *= 2.0;
7050: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7051: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
7052: cMax = cMax < 0 ? cEnd : cMax;
7053: for (c = cStart; c < cMax; ++c) {
7054: DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
7055: if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
7056: PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
7057: if (depth > 1) {
7058: DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
7059: if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
7060: PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
7061: }
7062: }
7063: return(0);
7064: }
7066: static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
7067: {
7068: PetscInt i,l,n;
7069: const PetscInt *cone;
7073: *missingPoint = -1;
7074: DMPlexGetConeSize(dm, p, &n);
7075: DMPlexGetCone(dm, p, &cone);
7076: for (i=0; i<n; i++) {
7077: PetscFindInt(cone[i], npoints, points, &l);
7078: if (l < 0) {
7079: *missingPoint = cone[i];
7080: break;
7081: }
7082: }
7083: return(0);
7084: }
7086: /*@
7087: DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
7089: Input Parameters:
7090: . dm - The DMPlex object
7092: Notes:
7093: This is mainly intended for debugging/testing purposes.
7094: It currently checks only meshes with no partition overlapping.
7096: Level: developer
7098: .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
7099: @*/
7100: PetscErrorCode DMPlexCheckPointSF(DM dm)
7101: {
7102: PetscSF sf;
7103: PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
7104: const PetscInt *locals;
7105: PetscErrorCode ierr;
7109: DMPlexGetDepth(dm, &depth);
7110: DMGetPointSF(dm, &sf);
7111: DMPlexGetOverlap(dm, &d);
7112: if (d) {
7113: PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");
7114: return(0);
7115: }
7116: PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);
7118: /* 1) check there are no faces in 2D, cells in 3D, in interface */
7119: DMPlexGetVTKCellHeight(dm, &d);
7120: DMPlexGetHeightStratum(dm, d, &plo, &phi);
7121: for (i=0; i<nleaves; i++) {
7122: p = locals[i];
7123: if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
7124: }
7126: /* 2) if some point is in interface, then all its cone points must be also in interface */
7127: for (i=0; i<nleaves; i++) {
7128: p = locals[i];
7129: DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);
7130: if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
7131: }
7132: return(0);
7133: }
7135: typedef struct cell_stats
7136: {
7137: PetscReal min, max, sum, squaresum;
7138: PetscInt count;
7139: } cell_stats_t;
7141: static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
7142: {
7143: PetscInt i, N = *len;
7145: for (i = 0; i < N; i++) {
7146: cell_stats_t *A = (cell_stats_t *) a;
7147: cell_stats_t *B = (cell_stats_t *) b;
7149: B->min = PetscMin(A->min,B->min);
7150: B->max = PetscMax(A->max,B->max);
7151: B->sum += A->sum;
7152: B->squaresum += A->squaresum;
7153: B->count += A->count;
7154: }
7155: }
7157: /*@
7158: DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
7160: Collective on dm
7162: Input Parameters:
7163: + dm - The DMPlex object
7164: . output - If true, statistics will be displayed on stdout
7165: - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
7167: Note: This is mainly intended for debugging/testing purposes.
7169: Level: developer
7171: .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
7172: @*/
7173: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
7174: {
7175: DM dmCoarse;
7176: cell_stats_t stats, globalStats;
7177: MPI_Comm comm = PetscObjectComm((PetscObject)dm);
7178: PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
7179: PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
7180: PetscInt cdim, cStart, cEnd, cMax, c, eStart, eEnd, count = 0;
7181: PetscMPIInt rank,size;
7186: stats.min = PETSC_MAX_REAL;
7187: stats.max = PETSC_MIN_REAL;
7188: stats.sum = stats.squaresum = 0.;
7189: stats.count = 0;
7191: MPI_Comm_size(comm, &size);
7192: MPI_Comm_rank(comm, &rank);
7193: DMGetCoordinateDim(dm,&cdim);
7194: PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);
7195: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
7196: DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);
7197: DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
7198: cMax = cMax < 0 ? cEnd : cMax;
7199: for (c = cStart; c < cMax; c++) {
7200: PetscInt i;
7201: PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
7203: DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
7204: if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
7205: for (i = 0; i < PetscSqr(cdim); ++i) {
7206: frobJ += J[i] * J[i];
7207: frobInvJ += invJ[i] * invJ[i];
7208: }
7209: cond2 = frobJ * frobInvJ;
7210: cond = PetscSqrtReal(cond2);
7212: stats.min = PetscMin(stats.min,cond);
7213: stats.max = PetscMax(stats.max,cond);
7214: stats.sum += cond;
7215: stats.squaresum += cond2;
7216: stats.count++;
7217: if (output && cond > limit) {
7218: PetscSection coordSection;
7219: Vec coordsLocal;
7220: PetscScalar *coords = NULL;
7221: PetscInt Nv, d, clSize, cl, *closure = NULL;
7223: DMGetCoordinatesLocal(dm, &coordsLocal);
7224: DMGetCoordinateSection(dm, &coordSection);
7225: DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7226: PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);
7227: for (i = 0; i < Nv/cdim; ++i) {
7228: PetscSynchronizedPrintf(comm, " Vertex %D: (", i);
7229: for (d = 0; d < cdim; ++d) {
7230: if (d > 0) {PetscSynchronizedPrintf(comm, ", ");}
7231: PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));
7232: }
7233: PetscSynchronizedPrintf(comm, ")\n");
7234: }
7235: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7236: for (cl = 0; cl < clSize*2; cl += 2) {
7237: const PetscInt edge = closure[cl];
7239: if ((edge >= eStart) && (edge < eEnd)) {
7240: PetscReal len;
7242: DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);
7243: PetscSynchronizedPrintf(comm, " Edge %D: length %g\n", edge, (double) len);
7244: }
7245: }
7246: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7247: DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7248: }
7249: }
7250: if (output) {PetscSynchronizedFlush(comm, NULL);}
7252: if (size > 1) {
7253: PetscMPIInt blockLengths[2] = {4,1};
7254: MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
7255: MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType;
7256: MPI_Op statReduce;
7258: MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
7259: MPI_Type_commit(&statType);
7260: MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
7261: MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
7262: MPI_Op_free(&statReduce);
7263: MPI_Type_free(&statType);
7264: } else {
7265: PetscArraycpy(&globalStats,&stats,1);
7266: }
7267: if (!rank) {
7268: count = globalStats.count;
7269: min = globalStats.min;
7270: max = globalStats.max;
7271: mean = globalStats.sum / globalStats.count;
7272: stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
7273: }
7275: if (output) {
7276: 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);
7277: }
7278: PetscFree2(J,invJ);
7280: DMGetCoarseDM(dm,&dmCoarse);
7281: if (dmCoarse) {
7282: PetscBool isplex;
7284: PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
7285: if (isplex) {
7286: DMPlexCheckCellShape(dmCoarse,output,condLimit);
7287: }
7288: }
7289: return(0);
7290: }
7292: /* Pointwise interpolation
7293: Just code FEM for now
7294: u^f = I u^c
7295: sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
7296: u^f_i = sum_j psi^f_i I phi^c_j u^c_j
7297: I_{ij} = psi^f_i phi^c_j
7298: */
7299: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
7300: {
7301: PetscSection gsc, gsf;
7302: PetscInt m, n;
7303: void *ctx;
7304: DM cdm;
7305: PetscBool regular, ismatis;
7309: DMGetGlobalSection(dmFine, &gsf);
7310: PetscSectionGetConstrainedStorageSize(gsf, &m);
7311: DMGetGlobalSection(dmCoarse, &gsc);
7312: PetscSectionGetConstrainedStorageSize(gsc, &n);
7314: PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
7315: MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
7316: MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7317: MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
7318: DMGetApplicationContext(dmFine, &ctx);
7320: DMGetCoarseDM(dmFine, &cdm);
7321: DMPlexGetRegularRefinement(dmFine, ®ular);
7322: if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
7323: else {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
7324: MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
7325: if (scaling) {
7326: /* Use naive scaling */
7327: DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
7328: }
7329: return(0);
7330: }
7332: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
7333: {
7335: VecScatter ctx;
7338: DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
7339: MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
7340: VecScatterDestroy(&ctx);
7341: return(0);
7342: }
7344: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
7345: {
7346: PetscSection gsc, gsf;
7347: PetscInt m, n;
7348: void *ctx;
7349: DM cdm;
7350: PetscBool regular;
7354: DMGetGlobalSection(dmFine, &gsf);
7355: PetscSectionGetConstrainedStorageSize(gsf, &m);
7356: DMGetGlobalSection(dmCoarse, &gsc);
7357: PetscSectionGetConstrainedStorageSize(gsc, &n);
7359: MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
7360: MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7361: MatSetType(*mass, dmCoarse->mattype);
7362: DMGetApplicationContext(dmFine, &ctx);
7364: DMGetCoarseDM(dmFine, &cdm);
7365: DMPlexGetRegularRefinement(dmFine, ®ular);
7366: if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
7367: else {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
7368: MatViewFromOptions(*mass, NULL, "-mass_mat_view");
7369: return(0);
7370: }
7372: /*@
7373: DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7375: Input Parameter:
7376: . dm - The DMPlex object
7378: Output Parameter:
7379: . regular - The flag
7381: Level: intermediate
7383: .seealso: DMPlexSetRegularRefinement()
7384: @*/
7385: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7386: {
7390: *regular = ((DM_Plex *) dm->data)->regularRefinement;
7391: return(0);
7392: }
7394: /*@
7395: DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7397: Input Parameters:
7398: + dm - The DMPlex object
7399: - regular - The flag
7401: Level: intermediate
7403: .seealso: DMPlexGetRegularRefinement()
7404: @*/
7405: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7406: {
7409: ((DM_Plex *) dm->data)->regularRefinement = regular;
7410: return(0);
7411: }
7413: /* anchors */
7414: /*@
7415: DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to
7416: call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
7418: not collective
7420: Input Parameters:
7421: . dm - The DMPlex object
7423: Output Parameters:
7424: + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
7425: - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
7428: Level: intermediate
7430: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7431: @*/
7432: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7433: {
7434: DM_Plex *plex = (DM_Plex *)dm->data;
7439: if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7440: if (anchorSection) *anchorSection = plex->anchorSection;
7441: if (anchorIS) *anchorIS = plex->anchorIS;
7442: return(0);
7443: }
7445: /*@
7446: DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions,
7447: when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
7448: point's degrees of freedom to be a linear combination of other points' degrees of freedom.
7450: After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
7451: DMGetConstraints() and filling in the entries in the constraint matrix.
7453: collective on dm
7455: Input Parameters:
7456: + dm - The DMPlex object
7457: . 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).
7458: - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative).
7460: The reference counts of anchorSection and anchorIS are incremented.
7462: Level: intermediate
7464: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7465: @*/
7466: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7467: {
7468: DM_Plex *plex = (DM_Plex *)dm->data;
7469: PetscMPIInt result;
7474: if (anchorSection) {
7476: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7477: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7478: }
7479: if (anchorIS) {
7481: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7482: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7483: }
7485: PetscObjectReference((PetscObject)anchorSection);
7486: PetscSectionDestroy(&plex->anchorSection);
7487: plex->anchorSection = anchorSection;
7489: PetscObjectReference((PetscObject)anchorIS);
7490: ISDestroy(&plex->anchorIS);
7491: plex->anchorIS = anchorIS;
7493: #if defined(PETSC_USE_DEBUG)
7494: if (anchorIS && anchorSection) {
7495: PetscInt size, a, pStart, pEnd;
7496: const PetscInt *anchors;
7498: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7499: ISGetLocalSize(anchorIS,&size);
7500: ISGetIndices(anchorIS,&anchors);
7501: for (a = 0; a < size; a++) {
7502: PetscInt p;
7504: p = anchors[a];
7505: if (p >= pStart && p < pEnd) {
7506: PetscInt dof;
7508: PetscSectionGetDof(anchorSection,p,&dof);
7509: if (dof) {
7510: PetscErrorCode ierr2;
7512: ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7513: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7514: }
7515: }
7516: }
7517: ISRestoreIndices(anchorIS,&anchors);
7518: }
7519: #endif
7520: /* reset the generic constraints */
7521: DMSetDefaultConstraints(dm,NULL,NULL);
7522: return(0);
7523: }
7525: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7526: {
7527: PetscSection anchorSection;
7528: PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
7533: DMPlexGetAnchors(dm,&anchorSection,NULL);
7534: PetscSectionCreate(PETSC_COMM_SELF,cSec);
7535: PetscSectionGetNumFields(section,&numFields);
7536: if (numFields) {
7537: PetscInt f;
7538: PetscSectionSetNumFields(*cSec,numFields);
7540: for (f = 0; f < numFields; f++) {
7541: PetscInt numComp;
7543: PetscSectionGetFieldComponents(section,f,&numComp);
7544: PetscSectionSetFieldComponents(*cSec,f,numComp);
7545: }
7546: }
7547: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7548: PetscSectionGetChart(section,&sStart,&sEnd);
7549: pStart = PetscMax(pStart,sStart);
7550: pEnd = PetscMin(pEnd,sEnd);
7551: pEnd = PetscMax(pStart,pEnd);
7552: PetscSectionSetChart(*cSec,pStart,pEnd);
7553: for (p = pStart; p < pEnd; p++) {
7554: PetscSectionGetDof(anchorSection,p,&dof);
7555: if (dof) {
7556: PetscSectionGetDof(section,p,&dof);
7557: PetscSectionSetDof(*cSec,p,dof);
7558: for (f = 0; f < numFields; f++) {
7559: PetscSectionGetFieldDof(section,p,f,&dof);
7560: PetscSectionSetFieldDof(*cSec,p,f,dof);
7561: }
7562: }
7563: }
7564: PetscSectionSetUp(*cSec);
7565: return(0);
7566: }
7568: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7569: {
7570: PetscSection aSec;
7571: PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7572: const PetscInt *anchors;
7573: PetscInt numFields, f;
7574: IS aIS;
7579: PetscSectionGetStorageSize(cSec, &m);
7580: PetscSectionGetStorageSize(section, &n);
7581: MatCreate(PETSC_COMM_SELF,cMat);
7582: MatSetSizes(*cMat,m,n,m,n);
7583: MatSetType(*cMat,MATSEQAIJ);
7584: DMPlexGetAnchors(dm,&aSec,&aIS);
7585: ISGetIndices(aIS,&anchors);
7586: /* cSec will be a subset of aSec and section */
7587: PetscSectionGetChart(cSec,&pStart,&pEnd);
7588: PetscMalloc1(m+1,&i);
7589: i[0] = 0;
7590: PetscSectionGetNumFields(section,&numFields);
7591: for (p = pStart; p < pEnd; p++) {
7592: PetscInt rDof, rOff, r;
7594: PetscSectionGetDof(aSec,p,&rDof);
7595: if (!rDof) continue;
7596: PetscSectionGetOffset(aSec,p,&rOff);
7597: if (numFields) {
7598: for (f = 0; f < numFields; f++) {
7599: annz = 0;
7600: for (r = 0; r < rDof; r++) {
7601: a = anchors[rOff + r];
7602: PetscSectionGetFieldDof(section,a,f,&aDof);
7603: annz += aDof;
7604: }
7605: PetscSectionGetFieldDof(cSec,p,f,&dof);
7606: PetscSectionGetFieldOffset(cSec,p,f,&off);
7607: for (q = 0; q < dof; q++) {
7608: i[off + q + 1] = i[off + q] + annz;
7609: }
7610: }
7611: }
7612: else {
7613: annz = 0;
7614: for (q = 0; q < dof; q++) {
7615: a = anchors[off + q];
7616: PetscSectionGetDof(section,a,&aDof);
7617: annz += aDof;
7618: }
7619: PetscSectionGetDof(cSec,p,&dof);
7620: PetscSectionGetOffset(cSec,p,&off);
7621: for (q = 0; q < dof; q++) {
7622: i[off + q + 1] = i[off + q] + annz;
7623: }
7624: }
7625: }
7626: nnz = i[m];
7627: PetscMalloc1(nnz,&j);
7628: offset = 0;
7629: for (p = pStart; p < pEnd; p++) {
7630: if (numFields) {
7631: for (f = 0; f < numFields; f++) {
7632: PetscSectionGetFieldDof(cSec,p,f,&dof);
7633: for (q = 0; q < dof; q++) {
7634: PetscInt rDof, rOff, r;
7635: PetscSectionGetDof(aSec,p,&rDof);
7636: PetscSectionGetOffset(aSec,p,&rOff);
7637: for (r = 0; r < rDof; r++) {
7638: PetscInt s;
7640: a = anchors[rOff + r];
7641: PetscSectionGetFieldDof(section,a,f,&aDof);
7642: PetscSectionGetFieldOffset(section,a,f,&aOff);
7643: for (s = 0; s < aDof; s++) {
7644: j[offset++] = aOff + s;
7645: }
7646: }
7647: }
7648: }
7649: }
7650: else {
7651: PetscSectionGetDof(cSec,p,&dof);
7652: for (q = 0; q < dof; q++) {
7653: PetscInt rDof, rOff, r;
7654: PetscSectionGetDof(aSec,p,&rDof);
7655: PetscSectionGetOffset(aSec,p,&rOff);
7656: for (r = 0; r < rDof; r++) {
7657: PetscInt s;
7659: a = anchors[rOff + r];
7660: PetscSectionGetDof(section,a,&aDof);
7661: PetscSectionGetOffset(section,a,&aOff);
7662: for (s = 0; s < aDof; s++) {
7663: j[offset++] = aOff + s;
7664: }
7665: }
7666: }
7667: }
7668: }
7669: MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7670: PetscFree(i);
7671: PetscFree(j);
7672: ISRestoreIndices(aIS,&anchors);
7673: return(0);
7674: }
7676: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7677: {
7678: DM_Plex *plex = (DM_Plex *)dm->data;
7679: PetscSection anchorSection, section, cSec;
7680: Mat cMat;
7685: DMPlexGetAnchors(dm,&anchorSection,NULL);
7686: if (anchorSection) {
7687: PetscInt Nf;
7689: DMGetLocalSection(dm,§ion);
7690: DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7691: DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7692: DMGetNumFields(dm,&Nf);
7693: if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7694: DMSetDefaultConstraints(dm,cSec,cMat);
7695: PetscSectionDestroy(&cSec);
7696: MatDestroy(&cMat);
7697: }
7698: return(0);
7699: }
7701: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7702: {
7703: IS subis;
7704: PetscSection section, subsection;
7708: DMGetLocalSection(dm, §ion);
7709: if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7710: if (!subdm) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7711: /* Create subdomain */
7712: DMPlexFilter(dm, label, value, subdm);
7713: /* Create submodel */
7714: DMPlexCreateSubpointIS(*subdm, &subis);
7715: PetscSectionCreateSubmeshSection(section, subis, &subsection);
7716: ISDestroy(&subis);
7717: DMSetLocalSection(*subdm, subsection);
7718: PetscSectionDestroy(&subsection);
7719: DMCopyDisc(dm, *subdm);
7720: /* Create map from submodel to global model */
7721: if (is) {
7722: PetscSection sectionGlobal, subsectionGlobal;
7723: IS spIS;
7724: const PetscInt *spmap;
7725: PetscInt *subIndices;
7726: PetscInt subSize = 0, subOff = 0, pStart, pEnd, p;
7727: PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
7729: DMPlexCreateSubpointIS(*subdm, &spIS);
7730: ISGetIndices(spIS, &spmap);
7731: PetscSectionGetNumFields(section, &Nf);
7732: DMGetGlobalSection(dm, §ionGlobal);
7733: DMGetGlobalSection(*subdm, &subsectionGlobal);
7734: PetscSectionGetChart(subsection, &pStart, &pEnd);
7735: for (p = pStart; p < pEnd; ++p) {
7736: PetscInt gdof, pSubSize = 0;
7738: PetscSectionGetDof(sectionGlobal, p, &gdof);
7739: if (gdof > 0) {
7740: for (f = 0; f < Nf; ++f) {
7741: PetscInt fdof, fcdof;
7743: PetscSectionGetFieldDof(subsection, p, f, &fdof);
7744: PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7745: pSubSize += fdof-fcdof;
7746: }
7747: subSize += pSubSize;
7748: if (pSubSize) {
7749: if (bs < 0) {
7750: bs = pSubSize;
7751: } else if (bs != pSubSize) {
7752: /* Layout does not admit a pointwise block size */
7753: bs = 1;
7754: }
7755: }
7756: }
7757: }
7758: /* Must have same blocksize on all procs (some might have no points) */
7759: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7760: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7761: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7762: else {bs = bsMinMax[0];}
7763: PetscMalloc1(subSize, &subIndices);
7764: for (p = pStart; p < pEnd; ++p) {
7765: PetscInt gdof, goff;
7767: PetscSectionGetDof(subsectionGlobal, p, &gdof);
7768: if (gdof > 0) {
7769: const PetscInt point = spmap[p];
7771: PetscSectionGetOffset(sectionGlobal, point, &goff);
7772: for (f = 0; f < Nf; ++f) {
7773: PetscInt fdof, fcdof, fc, f2, poff = 0;
7775: /* Can get rid of this loop by storing field information in the global section */
7776: for (f2 = 0; f2 < f; ++f2) {
7777: PetscSectionGetFieldDof(section, p, f2, &fdof);
7778: PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7779: poff += fdof-fcdof;
7780: }
7781: PetscSectionGetFieldDof(section, p, f, &fdof);
7782: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7783: for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7784: subIndices[subOff] = goff+poff+fc;
7785: }
7786: }
7787: }
7788: }
7789: ISRestoreIndices(spIS, &spmap);
7790: ISDestroy(&spIS);
7791: ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7792: if (bs > 1) {
7793: /* We need to check that the block size does not come from non-contiguous fields */
7794: PetscInt i, j, set = 1;
7795: for (i = 0; i < subSize; i += bs) {
7796: for (j = 0; j < bs; ++j) {
7797: if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7798: }
7799: }
7800: if (set) {ISSetBlockSize(*is, bs);}
7801: }
7802: /* Attach nullspace */
7803: for (f = 0; f < Nf; ++f) {
7804: (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7805: if ((*subdm)->nullspaceConstructors[f]) break;
7806: }
7807: if (f < Nf) {
7808: MatNullSpace nullSpace;
7810: (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7811: PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7812: MatNullSpaceDestroy(&nullSpace);
7813: }
7814: }
7815: return(0);
7816: }