Actual source code: plex.c
petsc-3.8.0 2017-09-26
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>
9: /* Logging support */
10: PetscLogEvent DMPLEX_Interpolate, PETSCPARTITIONER_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_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;
12: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
14: /*@
15: DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells.
16: 3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D.
18: Collective
20: Input Parameters:
21: . dm - The DMPlex object
23: Output Parameters:
24: . dmRefined - The refined DMPlex object
26: Note: Returns NULL if the mesh is already a tensor product mesh.
28: Level: intermediate
30: .seealso: DMPlexCreate(), DMPlexSetRefinementUniform()
31: @*/
32: PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined)
33: {
34: PetscInt dim, cMax, fMax, cStart, cEnd, coneSize;
35: CellRefiner cellRefiner;
36: PetscBool lop, allnoop, localized;
37: PetscErrorCode ierr;
41: DMGetDimension(dm, &dim);
42: DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
43: if (cMax >= 0 || fMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle hybrid meshes yet");
44: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
45: if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
46: else {
47: DMPlexGetConeSize(dm,cStart,&coneSize);
48: switch (dim) {
49: case 1:
50: cellRefiner = REFINER_NOOP;
51: break;
52: case 2:
53: switch (coneSize) {
54: case 3:
55: cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
56: break;
57: case 4:
58: cellRefiner = REFINER_NOOP;
59: break;
60: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
61: }
62: break;
63: case 3:
64: switch (coneSize) {
65: case 4:
66: cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
67: break;
68: case 6:
69: cellRefiner = REFINER_NOOP;
70: break;
71: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
72: }
73: break;
74: default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
75: }
76: }
77: /* return if we don't need to refine */
78: lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
79: MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
80: if (allnoop) {
81: *dmRefined = NULL;
82: return(0);
83: }
84: DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
85: DMCopyBoundary(dm, *dmRefined);
86: DMGetCoordinatesLocalized(dm, &localized);
87: if (localized) {
88: DMLocalizeCoordinates(*dmRefined);
89: }
90: return(0);
91: }
93: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
94: {
95: PetscInt dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior, vdof = 0, cdof = 0;
99: *ft = PETSC_VTK_POINT_FIELD;
100: DMGetDimension(dm, &dim);
101: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
102: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
103: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
104: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
105: PetscSectionGetChart(section, &pStart, &pEnd);
106: if (field >= 0) {
107: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vdof);}
108: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &cdof);}
109: } else {
110: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vdof);}
111: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &cdof);}
112: }
113: if (vdof) {
114: *sStart = vStart;
115: *sEnd = vEnd;
116: if (vdof == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
117: else *ft = PETSC_VTK_POINT_FIELD;
118: } else if (cdof) {
119: *sStart = cStart;
120: *sEnd = cEnd;
121: if (cdof == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
122: else *ft = PETSC_VTK_CELL_FIELD;
123: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
124: return(0);
125: }
127: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
128: {
129: DM dm;
130: PetscSection s;
131: PetscDraw draw, popup;
132: DM cdm;
133: PetscSection coordSection;
134: Vec coordinates;
135: const PetscScalar *coords, *array;
136: PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
137: PetscReal vbound[2], time;
138: PetscBool isnull, flg;
139: PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
140: const char *name;
141: char title[PETSC_MAX_PATH_LEN];
142: PetscErrorCode ierr;
145: PetscViewerDrawGetDraw(viewer, 0, &draw);
146: PetscDrawIsNull(draw, &isnull);
147: if (isnull) return(0);
149: VecGetDM(v, &dm);
150: DMGetCoordinateDim(dm, &dim);
151: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
152: DMGetDefaultSection(dm, &s);
153: PetscSectionGetNumFields(s, &Nf);
154: DMGetCoarsenLevel(dm, &level);
155: DMGetCoordinateDM(dm, &cdm);
156: DMGetDefaultSection(cdm, &coordSection);
157: DMGetCoordinatesLocal(dm, &coordinates);
158: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
159: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
161: PetscObjectGetName((PetscObject) v, &name);
162: DMGetOutputSequenceNumber(dm, &step, &time);
164: VecGetLocalSize(coordinates, &N);
165: VecGetArrayRead(coordinates, &coords);
166: for (c = 0; c < N; c += dim) {
167: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
168: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
169: }
170: VecRestoreArrayRead(coordinates, &coords);
171: PetscDrawClear(draw);
173: /* Could implement something like DMDASelectFields() */
174: for (f = 0; f < Nf; ++f) {
175: DM fdm = dm;
176: Vec fv = v;
177: IS fis;
178: char prefix[PETSC_MAX_PATH_LEN];
179: const char *fname;
181: PetscSectionGetFieldComponents(s, f, &Nc);
182: PetscSectionGetFieldName(s, f, &fname);
184: if (v->hdr.prefix) {PetscStrcpy(prefix, v->hdr.prefix);}
185: else {prefix[0] = '\0';}
186: if (Nf > 1) {
187: DMCreateSubDM(dm, 1, &f, &fis, &fdm);
188: VecGetSubVector(v, fis, &fv);
189: PetscStrcat(prefix, fname);
190: PetscStrcat(prefix, "_");
191: }
192: for (comp = 0; comp < Nc; ++comp, ++w) {
193: PetscInt nmax = 2;
195: PetscViewerDrawGetDraw(viewer, w, &draw);
196: if (Nc > 1) {PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);}
197: else {PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);}
198: PetscDrawSetTitle(draw, title);
200: /* TODO Get max and min only for this component */
201: PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
202: if (!flg) {
203: VecMin(fv, NULL, &vbound[0]);
204: VecMax(fv, NULL, &vbound[1]);
205: if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
206: }
207: PetscDrawGetPopup(draw, &popup);
208: PetscDrawScalePopup(popup, vbound[0], vbound[1]);
209: PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
211: VecGetArrayRead(fv, &array);
212: for (c = cStart; c < cEnd; ++c) {
213: PetscScalar *coords = NULL, *a = NULL;
214: PetscInt numCoords, color[4] = {-1,-1,-1,-1};
216: DMPlexPointLocalRead(fdm, c, array, &a);
217: if (a) {
218: color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
219: color[1] = color[2] = color[3] = color[0];
220: } else {
221: PetscScalar *vals = NULL;
222: PetscInt numVals, va;
224: DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
225: 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);
226: switch (numVals/Nc) {
227: case 3: /* P1 Triangle */
228: case 4: /* P1 Quadrangle */
229: for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
230: break;
231: case 6: /* P2 Triangle */
232: case 8: /* P2 Quadrangle */
233: for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
234: break;
235: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
236: }
237: DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
238: }
239: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
240: switch (numCoords) {
241: case 6:
242: 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]);
243: break;
244: case 8:
245: 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]);
246: 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]);
247: break;
248: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
249: }
250: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
251: }
252: VecRestoreArrayRead(fv, &array);
253: PetscDrawFlush(draw);
254: PetscDrawPause(draw);
255: PetscDrawSave(draw);
256: }
257: if (Nf > 1) {
258: VecRestoreSubVector(v, fis, &fv);
259: ISDestroy(&fis);
260: DMDestroy(&fdm);
261: }
262: }
263: return(0);
264: }
266: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
267: {
268: DM dm;
269: PetscBool isvtk, ishdf5, isdraw, isseq, isglvis;
273: VecGetDM(v, &dm);
274: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
275: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
276: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
277: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
278: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
279: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
280: if (isvtk || ishdf5 || isglvis) {
281: PetscInt numFields;
282: PetscBool fem = PETSC_FALSE;
284: DMGetNumFields(dm, &numFields);
285: if (numFields) {
286: PetscObject fe;
288: DMGetField(dm, 0, &fe);
289: if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE;
290: }
291: if (fem) {DMPlexInsertBoundaryValues(dm, PETSC_TRUE, v, 0.0, NULL, NULL, NULL);}
292: }
293: if (isvtk) {
294: PetscSection section;
295: PetscViewerVTKFieldType ft;
296: PetscInt pStart, pEnd;
298: DMGetDefaultSection(dm, §ion);
299: DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
300: PetscObjectReference((PetscObject) v); /* viewer drops reference */
301: PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
302: } else if (ishdf5) {
303: #if defined(PETSC_HAVE_HDF5)
304: VecView_Plex_Local_HDF5_Internal(v, viewer);
305: #else
306: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
307: #endif
308: } else if (isglvis) {
309: VecView_GLVis(v, viewer);
310: } else if (isdraw) {
311: VecView_Plex_Local_Draw(v, viewer);
312: } else {
313: if (isseq) {VecView_Seq(v, viewer);}
314: else {VecView_MPI(v, viewer);}
315: }
316: return(0);
317: }
319: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
320: {
321: DM dm;
322: PetscReal time = 0.0;
323: PetscBool isvtk, ishdf5, isdraw, isseq, isglvis;
327: VecGetDM(v, &dm);
328: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
329: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
330: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
331: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
332: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
333: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
334: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
335: if (isvtk || isglvis) {
336: PetscInt num;
337: Vec locv;
338: const char *name;
340: DMGetLocalVector(dm, &locv);
341: PetscObjectGetName((PetscObject) v, &name);
342: PetscObjectSetName((PetscObject) locv, name);
343: DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
344: DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
345: DMGetOutputSequenceNumber(dm, &num, &time);
346: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
347: PetscViewerGLVisSetSnapId(viewer, num);
348: VecView_Plex_Local(locv, viewer);
349: DMRestoreLocalVector(dm, &locv);
350: } else if (ishdf5) {
351: #if defined(PETSC_HAVE_HDF5)
352: VecView_Plex_HDF5_Internal(v, viewer);
353: #else
354: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
355: #endif
356: } else if (isdraw) {
357: Vec locv;
358: const char *name;
360: DMGetLocalVector(dm, &locv);
361: PetscObjectGetName((PetscObject) v, &name);
362: PetscObjectSetName((PetscObject) locv, name);
363: DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
364: DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
365: DMGetOutputSequenceNumber(dm, NULL, &time);
366: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
367: VecView_Plex_Local(locv, viewer);
368: DMRestoreLocalVector(dm, &locv);
369: } else {
370: if (isseq) {VecView_Seq(v, viewer);}
371: else {VecView_MPI(v, viewer);}
372: }
373: return(0);
374: }
376: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
377: {
378: DM dm;
379: MPI_Comm comm;
380: PetscViewerFormat format;
381: Vec v;
382: PetscBool isvtk, ishdf5;
383: PetscErrorCode ierr;
386: VecGetDM(originalv, &dm);
387: PetscObjectGetComm((PetscObject) originalv, &comm);
388: if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
389: PetscViewerGetFormat(viewer, &format);
390: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
391: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
392: if (format == PETSC_VIEWER_NATIVE) {
393: const char *vecname;
394: PetscInt n, nroots;
396: if (dm->sfNatural) {
397: VecGetLocalSize(originalv, &n);
398: PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
399: if (n == nroots) {
400: DMGetGlobalVector(dm, &v);
401: DMPlexGlobalToNaturalBegin(dm, originalv, v);
402: DMPlexGlobalToNaturalEnd(dm, originalv, v);
403: PetscObjectGetName((PetscObject) originalv, &vecname);
404: PetscObjectSetName((PetscObject) v, vecname);
405: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
406: } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
407: } else {
408: /* we are viewing a natural DMPlex vec. */
409: v = originalv;
410: }
411: if (ishdf5) {
412: #if defined(PETSC_HAVE_HDF5)
413: VecView_Plex_HDF5_Native_Internal(v, viewer);
414: #else
415: SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
416: #endif
417: } else if (isvtk) {
418: SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
419: } else {
420: PetscBool isseq;
422: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
423: if (isseq) {VecView_Seq(v, viewer);}
424: else {VecView_MPI(v, viewer);}
425: }
426: if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
427: return(0);
428: }
430: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
431: {
432: DM dm;
433: PetscBool ishdf5;
437: VecGetDM(v, &dm);
438: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
439: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
440: if (ishdf5) {
441: DM dmBC;
442: Vec gv;
443: const char *name;
445: DMGetOutputDM(dm, &dmBC);
446: DMGetGlobalVector(dmBC, &gv);
447: PetscObjectGetName((PetscObject) v, &name);
448: PetscObjectSetName((PetscObject) gv, name);
449: VecLoad_Default(gv, viewer);
450: DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
451: DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
452: DMRestoreGlobalVector(dmBC, &gv);
453: } else {
454: VecLoad_Default(v, viewer);
455: }
456: return(0);
457: }
459: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
460: {
461: DM dm;
462: PetscBool ishdf5;
466: VecGetDM(v, &dm);
467: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
468: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
469: if (ishdf5) {
470: #if defined(PETSC_HAVE_HDF5)
471: VecLoad_Plex_HDF5_Internal(v, viewer);
472: #else
473: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
474: #endif
475: } else {
476: VecLoad_Default(v, viewer);
477: }
478: return(0);
479: }
481: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
482: {
483: DM dm;
484: PetscViewerFormat format;
485: PetscBool ishdf5;
486: PetscErrorCode ierr;
489: VecGetDM(originalv, &dm);
490: if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
491: PetscViewerGetFormat(viewer, &format);
492: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
493: if (format == PETSC_VIEWER_NATIVE) {
494: if (dm->sfNatural) {
495: if (ishdf5) {
496: #if defined(PETSC_HAVE_HDF5)
497: Vec v;
498: const char *vecname;
500: DMGetGlobalVector(dm, &v);
501: PetscObjectGetName((PetscObject) originalv, &vecname);
502: PetscObjectSetName((PetscObject) v, vecname);
503: VecLoad_Plex_HDF5_Native_Internal(v, viewer);
504: DMPlexNaturalToGlobalBegin(dm, v, originalv);
505: DMPlexNaturalToGlobalEnd(dm, v, originalv);
506: DMRestoreGlobalVector(dm, &v);
507: #else
508: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
509: #endif
510: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
511: }
512: }
513: return(0);
514: }
516: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
517: {
518: PetscSection coordSection;
519: Vec coordinates;
520: DMLabel depthLabel;
521: const char *name[4];
522: const PetscScalar *a;
523: PetscInt dim, pStart, pEnd, cStart, cEnd, c;
524: PetscErrorCode ierr;
527: DMGetDimension(dm, &dim);
528: DMGetCoordinatesLocal(dm, &coordinates);
529: DMGetCoordinateSection(dm, &coordSection);
530: DMPlexGetDepthLabel(dm, &depthLabel);
531: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
532: PetscSectionGetChart(coordSection, &pStart, &pEnd);
533: VecGetArrayRead(coordinates, &a);
534: name[0] = "vertex";
535: name[1] = "edge";
536: name[dim-1] = "face";
537: name[dim] = "cell";
538: for (c = cStart; c < cEnd; ++c) {
539: PetscInt *closure = NULL;
540: PetscInt closureSize, cl;
542: PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);
543: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
544: PetscViewerASCIIPushTab(viewer);
545: for (cl = 0; cl < closureSize*2; cl += 2) {
546: PetscInt point = closure[cl], depth, dof, off, d, p;
548: if ((point < pStart) || (point >= pEnd)) continue;
549: PetscSectionGetDof(coordSection, point, &dof);
550: if (!dof) continue;
551: DMLabelGetValue(depthLabel, point, &depth);
552: PetscSectionGetOffset(coordSection, point, &off);
553: PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
554: for (p = 0; p < dof/dim; ++p) {
555: PetscViewerASCIIPrintf(viewer, " (");
556: for (d = 0; d < dim; ++d) {
557: if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
558: PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
559: }
560: PetscViewerASCIIPrintf(viewer, ")");
561: }
562: PetscViewerASCIIPrintf(viewer, "\n");
563: }
564: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
565: PetscViewerASCIIPopTab(viewer);
566: }
567: VecRestoreArrayRead(coordinates, &a);
568: return(0);
569: }
571: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
572: {
573: DM_Plex *mesh = (DM_Plex*) dm->data;
574: DM cdm;
575: DMLabel markers;
576: PetscSection coordSection;
577: Vec coordinates;
578: PetscViewerFormat format;
579: PetscErrorCode ierr;
582: DMGetCoordinateDM(dm, &cdm);
583: DMGetDefaultSection(cdm, &coordSection);
584: DMGetCoordinatesLocal(dm, &coordinates);
585: PetscViewerGetFormat(viewer, &format);
586: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
587: const char *name;
588: PetscInt maxConeSize, maxSupportSize;
589: PetscInt pStart, pEnd, p;
590: PetscMPIInt rank, size;
592: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
593: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
594: PetscObjectGetName((PetscObject) dm, &name);
595: DMPlexGetChart(dm, &pStart, &pEnd);
596: DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
597: PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);
598: PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
599: PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
600: PetscViewerASCIIPushSynchronized(viewer);
601: PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);
602: for (p = pStart; p < pEnd; ++p) {
603: PetscInt dof, off, s;
605: PetscSectionGetDof(mesh->supportSection, p, &dof);
606: PetscSectionGetOffset(mesh->supportSection, p, &off);
607: for (s = off; s < off+dof; ++s) {
608: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
609: }
610: }
611: PetscViewerFlush(viewer);
612: PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
613: for (p = pStart; p < pEnd; ++p) {
614: PetscInt dof, off, c;
616: PetscSectionGetDof(mesh->coneSection, p, &dof);
617: PetscSectionGetOffset(mesh->coneSection, p, &off);
618: for (c = off; c < off+dof; ++c) {
619: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
620: }
621: }
622: PetscViewerFlush(viewer);
623: PetscViewerASCIIPopSynchronized(viewer);
624: PetscSectionGetChart(coordSection, &pStart, NULL);
625: if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
626: DMGetLabel(dm, "marker", &markers);
627: DMLabelView(markers,viewer);
628: if (size > 1) {
629: PetscSF sf;
631: DMGetPointSF(dm, &sf);
632: PetscSFView(sf, viewer);
633: }
634: PetscViewerFlush(viewer);
635: } else if (format == PETSC_VIEWER_ASCII_LATEX) {
636: const char *name, *color;
637: const char *defcolors[3] = {"gray", "orange", "green"};
638: const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
639: PetscReal scale = 2.0;
640: PetscBool useNumbers = PETSC_TRUE, useLabels, useColors;
641: double tcoords[3];
642: PetscScalar *coords;
643: PetscInt numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
644: PetscMPIInt rank, size;
645: char **names, **colors, **lcolors;
647: DMGetDimension(dm, &dim);
648: DMPlexGetDepth(dm, &depth);
649: DMGetNumLabels(dm, &numLabels);
650: numLabels = PetscMax(numLabels, 10);
651: numColors = 10;
652: numLColors = 10;
653: PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
654: PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
655: PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
656: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
657: if (!useLabels) numLabels = 0;
658: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
659: if (!useColors) {
660: numColors = 3;
661: for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
662: }
663: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
664: if (!useColors) {
665: numLColors = 4;
666: for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
667: }
668: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
669: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
670: PetscObjectGetName((PetscObject) dm, &name);
671: PetscViewerASCIIPrintf(viewer, "\
672: \\documentclass[tikz]{standalone}\n\n\
673: \\usepackage{pgflibraryshapes}\n\
674: \\usetikzlibrary{backgrounds}\n\
675: \\usetikzlibrary{arrows}\n\
676: \\begin{document}\n");
677: if (size > 1) {
678: PetscViewerASCIIPrintf(viewer, "%s for process ", name);
679: for (p = 0; p < size; ++p) {
680: if (p > 0 && p == size-1) {
681: PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
682: } else if (p > 0) {
683: PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
684: }
685: PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
686: }
687: PetscViewerASCIIPrintf(viewer, ".\n\n\n");
688: }
689: PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);
690: /* Plot vertices */
691: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
692: VecGetArray(coordinates, &coords);
693: PetscViewerASCIIPushSynchronized(viewer);
694: for (v = vStart; v < vEnd; ++v) {
695: PetscInt off, dof, d;
696: PetscBool isLabeled = PETSC_FALSE;
698: PetscSectionGetDof(coordSection, v, &dof);
699: PetscSectionGetOffset(coordSection, v, &off);
700: PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
701: if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
702: for (d = 0; d < dof; ++d) {
703: tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
704: tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
705: }
706: /* Rotate coordinates since PGF makes z point out of the page instead of up */
707: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
708: for (d = 0; d < dof; ++d) {
709: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
710: PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
711: }
712: color = colors[rank%numColors];
713: for (l = 0; l < numLabels; ++l) {
714: PetscInt val;
715: DMGetLabelValue(dm, names[l], v, &val);
716: if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
717: }
718: if (useNumbers) {
719: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
720: } else {
721: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
722: }
723: }
724: VecRestoreArray(coordinates, &coords);
725: PetscViewerFlush(viewer);
726: /* Plot edges */
727: if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
728: if (dim < 3 && useNumbers) {
729: VecGetArray(coordinates, &coords);
730: PetscViewerASCIIPrintf(viewer, "\\path\n");
731: for (e = eStart; e < eEnd; ++e) {
732: const PetscInt *cone;
733: PetscInt coneSize, offA, offB, dof, d;
735: DMPlexGetConeSize(dm, e, &coneSize);
736: if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
737: DMPlexGetCone(dm, e, &cone);
738: PetscSectionGetDof(coordSection, cone[0], &dof);
739: PetscSectionGetOffset(coordSection, cone[0], &offA);
740: PetscSectionGetOffset(coordSection, cone[1], &offB);
741: PetscViewerASCIISynchronizedPrintf(viewer, "(");
742: for (d = 0; d < dof; ++d) {
743: tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
744: tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
745: }
746: /* Rotate coordinates since PGF makes z point out of the page instead of up */
747: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
748: for (d = 0; d < dof; ++d) {
749: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
750: PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
751: }
752: color = colors[rank%numColors];
753: for (l = 0; l < numLabels; ++l) {
754: PetscInt val;
755: DMGetLabelValue(dm, names[l], v, &val);
756: if (val >= 0) {color = lcolors[l%numLColors]; break;}
757: }
758: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
759: }
760: VecRestoreArray(coordinates, &coords);
761: PetscViewerFlush(viewer);
762: PetscViewerASCIIPrintf(viewer, "(0,0);\n");
763: }
764: /* Plot cells */
765: if (dim == 3 || !useNumbers) {
766: for (e = eStart; e < eEnd; ++e) {
767: const PetscInt *cone;
769: color = colors[rank%numColors];
770: for (l = 0; l < numLabels; ++l) {
771: PetscInt val;
772: DMGetLabelValue(dm, names[l], e, &val);
773: if (val >= 0) {color = lcolors[l%numLColors]; break;}
774: }
775: DMPlexGetCone(dm, e, &cone);
776: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
777: }
778: } else {
779: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
780: for (c = cStart; c < cEnd; ++c) {
781: PetscInt *closure = NULL;
782: PetscInt closureSize, firstPoint = -1;
784: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
785: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
786: for (p = 0; p < closureSize*2; p += 2) {
787: const PetscInt point = closure[p];
789: if ((point < vStart) || (point >= vEnd)) continue;
790: if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
791: PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
792: if (firstPoint < 0) firstPoint = point;
793: }
794: /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
795: PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
796: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
797: }
798: }
799: PetscViewerFlush(viewer);
800: PetscViewerASCIIPopSynchronized(viewer);
801: PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
802: PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
803: for (l = 0; l < numLabels; ++l) {PetscFree(names[l]);}
804: for (c = 0; c < numColors; ++c) {PetscFree(colors[c]);}
805: for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
806: PetscFree3(names, colors, lcolors);
807: } else {
808: MPI_Comm comm;
809: PetscInt *sizes, *hybsizes;
810: PetscInt locDepth, depth, dim, d, pMax[4];
811: PetscInt pStart, pEnd, p;
812: PetscInt numLabels, l;
813: const char *name;
814: PetscMPIInt size;
816: PetscObjectGetComm((PetscObject)dm,&comm);
817: MPI_Comm_size(comm, &size);
818: DMGetDimension(dm, &dim);
819: PetscObjectGetName((PetscObject) dm, &name);
820: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);}
821: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);}
822: DMPlexGetDepth(dm, &locDepth);
823: MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
824: DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
825: PetscMalloc2(size,&sizes,size,&hybsizes);
826: if (depth == 1) {
827: DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
828: pEnd = pEnd - pStart;
829: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
830: PetscViewerASCIIPrintf(viewer, " %d-cells:", 0);
831: for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
832: PetscViewerASCIIPrintf(viewer, "\n");
833: DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
834: pEnd = pEnd - pStart;
835: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
836: PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);
837: for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
838: PetscViewerASCIIPrintf(viewer, "\n");
839: } else {
840: PetscMPIInt rank;
841: MPI_Comm_rank(comm, &rank);
842: for (d = 0; d <= dim; d++) {
843: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
844: pEnd -= pStart;
845: pMax[d] -= pStart;
846: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
847: MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
848: PetscViewerASCIIPrintf(viewer, " %D-cells:", d);
849: for (p = 0; p < size; ++p) {
850: if (!rank) {
851: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
852: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
853: }
854: }
855: PetscViewerASCIIPrintf(viewer, "\n");
856: }
857: }
858: PetscFree2(sizes,hybsizes);
859: DMGetNumLabels(dm, &numLabels);
860: if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
861: for (l = 0; l < numLabels; ++l) {
862: DMLabel label;
863: const char *name;
864: IS valueIS;
865: const PetscInt *values;
866: PetscInt numValues, v;
868: DMGetLabelName(dm, l, &name);
869: DMGetLabel(dm, name, &label);
870: DMLabelGetNumValues(label, &numValues);
871: PetscViewerASCIIPrintf(viewer, " %s: %D strata with value/size (", name, numValues);
872: DMLabelGetValueIS(label, &valueIS);
873: ISGetIndices(valueIS, &values);
874: PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
875: for (v = 0; v < numValues; ++v) {
876: PetscInt size;
878: DMLabelGetStratumSize(label, values[v], &size);
879: if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
880: PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
881: }
882: PetscViewerASCIIPrintf(viewer, ")\n");
883: PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
884: ISRestoreIndices(valueIS, &values);
885: ISDestroy(&valueIS);
886: }
887: DMGetCoarseDM(dm, &cdm);
888: if (cdm) {
889: PetscViewerASCIIPushTab(viewer);
890: DMPlexView_Ascii(cdm, viewer);
891: PetscViewerASCIIPopTab(viewer);
892: }
893: }
894: return(0);
895: }
897: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
898: {
899: PetscDraw draw;
900: DM cdm;
901: PetscSection coordSection;
902: Vec coordinates;
903: const PetscScalar *coords;
904: PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
905: PetscBool isnull;
906: PetscInt dim, vStart, vEnd, cStart, cEnd, c, N;
907: PetscErrorCode ierr;
910: DMGetCoordinateDim(dm, &dim);
911: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
912: DMGetCoordinateDM(dm, &cdm);
913: DMGetDefaultSection(cdm, &coordSection);
914: DMGetCoordinatesLocal(dm, &coordinates);
915: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
916: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
918: PetscViewerDrawGetDraw(viewer, 0, &draw);
919: PetscDrawIsNull(draw, &isnull);
920: if (isnull) return(0);
921: PetscDrawSetTitle(draw, "Mesh");
923: VecGetLocalSize(coordinates, &N);
924: VecGetArrayRead(coordinates, &coords);
925: for (c = 0; c < N; c += dim) {
926: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
927: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
928: }
929: VecRestoreArrayRead(coordinates, &coords);
930: PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
931: PetscDrawClear(draw);
933: for (c = cStart; c < cEnd; ++c) {
934: PetscScalar *coords = NULL;
935: PetscInt numCoords;
937: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
938: switch (numCoords) {
939: case 6:
940: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
941: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
942: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
943: break;
944: case 8:
945: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
946: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
947: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
948: PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
949: break;
950: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
951: }
952: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
953: }
954: PetscDrawFlush(draw);
955: PetscDrawPause(draw);
956: PetscDrawSave(draw);
957: return(0);
958: }
960: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
961: {
962: PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis;
963: PetscErrorCode ierr;
968: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
969: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
970: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
971: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
972: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
973: if (iascii) {
974: PetscViewerFormat format;
975: PetscViewerGetFormat(viewer, &format);
976: if (format == PETSC_VIEWER_ASCII_GLVIS) {
977: DMPlexView_GLVis(dm, viewer);
978: } else {
979: DMPlexView_Ascii(dm, viewer);
980: }
981: } else if (ishdf5) {
982: #if defined(PETSC_HAVE_HDF5)
983: PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
984: DMPlexView_HDF5_Internal(dm, viewer);
985: PetscViewerPopFormat(viewer);
986: #else
987: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
988: #endif
989: } else if (isvtk) {
990: DMPlexVTKWriteAll((PetscObject) dm,viewer);
991: } else if (isdraw) {
992: DMPlexView_Draw(dm, viewer);
993: } else if (isglvis) {
994: DMPlexView_GLVis(dm, viewer);
995: }
996: /* Optionally view the partition */
997: PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
998: if (flg) {
999: Vec ranks;
1000: DMPlexCreateRankField(dm, &ranks);
1001: VecView(ranks, viewer);
1002: VecDestroy(&ranks);
1003: }
1004: return(0);
1005: }
1007: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1008: {
1009: PetscBool isbinary, ishdf5;
1015: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
1016: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
1017: if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
1018: else if (ishdf5) {
1019: #if defined(PETSC_HAVE_HDF5)
1020: DMPlexLoad_HDF5_Internal(dm, viewer);
1021: #else
1022: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1023: #endif
1024: }
1025: return(0);
1026: }
1028: PetscErrorCode DMDestroy_Plex(DM dm)
1029: {
1030: DM_Plex *mesh = (DM_Plex*) dm->data;
1034: PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1035: PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1036: if (--mesh->refct > 0) return(0);
1037: PetscSectionDestroy(&mesh->coneSection);
1038: PetscFree(mesh->cones);
1039: PetscFree(mesh->coneOrientations);
1040: PetscSectionDestroy(&mesh->supportSection);
1041: PetscSectionDestroy(&mesh->subdomainSection);
1042: PetscFree(mesh->supports);
1043: PetscFree(mesh->facesTmp);
1044: PetscFree(mesh->tetgenOpts);
1045: PetscFree(mesh->triangleOpts);
1046: PetscPartitionerDestroy(&mesh->partitioner);
1047: DMLabelDestroy(&mesh->subpointMap);
1048: ISDestroy(&mesh->globalVertexNumbers);
1049: ISDestroy(&mesh->globalCellNumbers);
1050: PetscSectionDestroy(&mesh->anchorSection);
1051: ISDestroy(&mesh->anchorIS);
1052: PetscSectionDestroy(&mesh->parentSection);
1053: PetscFree(mesh->parents);
1054: PetscFree(mesh->childIDs);
1055: PetscSectionDestroy(&mesh->childSection);
1056: PetscFree(mesh->children);
1057: DMDestroy(&mesh->referenceTree);
1058: PetscGridHashDestroy(&mesh->lbox);
1059: /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1060: PetscFree(mesh);
1061: return(0);
1062: }
1064: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1065: {
1066: PetscSection sectionGlobal;
1067: PetscInt bs = -1, mbs;
1068: PetscInt localSize;
1069: PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1070: PetscErrorCode ierr;
1071: MatType mtype;
1072: ISLocalToGlobalMapping ltog;
1075: MatInitializePackage();
1076: mtype = dm->mattype;
1077: DMGetDefaultGlobalSection(dm, §ionGlobal);
1078: /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1079: PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1080: MatCreate(PetscObjectComm((PetscObject)dm), J);
1081: MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1082: MatSetType(*J, mtype);
1083: MatSetFromOptions(*J);
1084: MatGetBlockSize(*J, &mbs);
1085: if (mbs > 1) bs = mbs;
1086: PetscStrcmp(mtype, MATSHELL, &isShell);
1087: PetscStrcmp(mtype, MATBAIJ, &isBlock);
1088: PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1089: PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1090: PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1091: PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1092: PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1093: PetscStrcmp(mtype, MATIS, &isMatIS);
1094: if (!isShell) {
1095: PetscSection subSection;
1096: PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1097: PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin, *ltogidx, lsize;
1098: PetscInt pStart, pEnd, p, dof, cdof;
1100: /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
1101: if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
1102: PetscSection section;
1103: PetscInt size;
1105: DMGetDefaultSection(dm, §ion);
1106: PetscSectionGetStorageSize(section, &size);
1107: PetscMalloc1(size,<ogidx);
1108: DMPlexGetSubdomainSection(dm, &subSection);
1109: } else {
1110: DMGetLocalToGlobalMapping(dm,<og);
1111: }
1112: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1113: for (p = pStart, lsize = 0; p < pEnd; ++p) {
1114: PetscInt bdof;
1116: PetscSectionGetDof(sectionGlobal, p, &dof);
1117: PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1118: dof = dof < 0 ? -(dof+1) : dof;
1119: bdof = cdof && (dof-cdof) ? 1 : dof;
1120: if (dof) {
1121: if (bs < 0) {bs = bdof;}
1122: else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1123: }
1124: if (isMatIS) {
1125: PetscInt loff,c,off;
1126: PetscSectionGetOffset(subSection, p, &loff);
1127: PetscSectionGetOffset(sectionGlobal, p, &off);
1128: for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1129: }
1130: }
1131: /* Must have same blocksize on all procs (some might have no points) */
1132: bsLocal = bs;
1133: MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1134: bsLocal = bs < 0 ? bsMax : bs;
1135: MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
1136: if (bsMin != bsMax) {bs = 1;}
1137: else {bs = bsMax;}
1138: bs = bs < 0 ? 1 : bs;
1139: if (isMatIS) {
1140: PetscInt l;
1141: /* Must reduce indices by blocksize */
1142: if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1143: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, <og);
1144: }
1145: MatSetLocalToGlobalMapping(*J,ltog,ltog);
1146: if (isMatIS) {
1147: ISLocalToGlobalMappingDestroy(<og);
1148: }
1149: PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1150: DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1151: PetscFree4(dnz, onz, dnzu, onzu);
1152: }
1153: MatSetDM(*J, dm);
1154: return(0);
1155: }
1157: /*@
1158: DMPlexGetSubdomainSection - Returns the section associated with the subdomain
1160: Not collective
1162: Input Parameter:
1163: . mesh - The DMPlex
1165: Output Parameters:
1166: . subsection - The subdomain section
1168: Level: developer
1170: .seealso:
1171: @*/
1172: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1173: {
1174: DM_Plex *mesh = (DM_Plex*) dm->data;
1179: if (!mesh->subdomainSection) {
1180: PetscSection section;
1181: PetscSF sf;
1183: PetscSFCreate(PETSC_COMM_SELF,&sf);
1184: DMGetDefaultSection(dm,§ion);
1185: PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1186: PetscSFDestroy(&sf);
1187: }
1188: *subsection = mesh->subdomainSection;
1189: return(0);
1190: }
1192: /*@
1193: DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1195: Not collective
1197: Input Parameter:
1198: . mesh - The DMPlex
1200: Output Parameters:
1201: + pStart - The first mesh point
1202: - pEnd - The upper bound for mesh points
1204: Level: beginner
1206: .seealso: DMPlexCreate(), DMPlexSetChart()
1207: @*/
1208: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1209: {
1210: DM_Plex *mesh = (DM_Plex*) dm->data;
1215: PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1216: return(0);
1217: }
1219: /*@
1220: DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1222: Not collective
1224: Input Parameters:
1225: + mesh - The DMPlex
1226: . pStart - The first mesh point
1227: - pEnd - The upper bound for mesh points
1229: Output Parameters:
1231: Level: beginner
1233: .seealso: DMPlexCreate(), DMPlexGetChart()
1234: @*/
1235: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1236: {
1237: DM_Plex *mesh = (DM_Plex*) dm->data;
1242: PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1243: PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1244: return(0);
1245: }
1247: /*@
1248: DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1250: Not collective
1252: Input Parameters:
1253: + mesh - The DMPlex
1254: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1256: Output Parameter:
1257: . size - The cone size for point p
1259: Level: beginner
1261: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1262: @*/
1263: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1264: {
1265: DM_Plex *mesh = (DM_Plex*) dm->data;
1271: PetscSectionGetDof(mesh->coneSection, p, size);
1272: return(0);
1273: }
1275: /*@
1276: DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1278: Not collective
1280: Input Parameters:
1281: + mesh - The DMPlex
1282: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1283: - size - The cone size for point p
1285: Output Parameter:
1287: Note:
1288: This should be called after DMPlexSetChart().
1290: Level: beginner
1292: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1293: @*/
1294: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1295: {
1296: DM_Plex *mesh = (DM_Plex*) dm->data;
1301: PetscSectionSetDof(mesh->coneSection, p, size);
1303: mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1304: return(0);
1305: }
1307: /*@
1308: DMPlexAddConeSize - Add the given number of in-edges to this point in the Sieve DAG
1310: Not collective
1312: Input Parameters:
1313: + mesh - The DMPlex
1314: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1315: - size - The additional cone size for point p
1317: Output Parameter:
1319: Note:
1320: This should be called after DMPlexSetChart().
1322: Level: beginner
1324: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1325: @*/
1326: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1327: {
1328: DM_Plex *mesh = (DM_Plex*) dm->data;
1329: PetscInt csize;
1334: PetscSectionAddDof(mesh->coneSection, p, size);
1335: PetscSectionGetDof(mesh->coneSection, p, &csize);
1337: mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1338: return(0);
1339: }
1341: /*@C
1342: DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1344: Not collective
1346: Input Parameters:
1347: + mesh - The DMPlex
1348: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1350: Output Parameter:
1351: . cone - An array of points which are on the in-edges for point p
1353: Level: beginner
1355: Fortran Notes:
1356: Since it returns an array, this routine is only available in Fortran 90, and you must
1357: include petsc.h90 in your code.
1359: You must also call DMPlexRestoreCone() after you finish using the returned array.
1361: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1362: @*/
1363: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1364: {
1365: DM_Plex *mesh = (DM_Plex*) dm->data;
1366: PetscInt off;
1372: PetscSectionGetOffset(mesh->coneSection, p, &off);
1373: *cone = &mesh->cones[off];
1374: return(0);
1375: }
1377: /*@
1378: DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1380: Not collective
1382: Input Parameters:
1383: + mesh - The DMPlex
1384: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1385: - cone - An array of points which are on the in-edges for point p
1387: Output Parameter:
1389: Note:
1390: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1392: Level: beginner
1394: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1395: @*/
1396: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1397: {
1398: DM_Plex *mesh = (DM_Plex*) dm->data;
1399: PetscInt pStart, pEnd;
1400: PetscInt dof, off, c;
1405: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1406: PetscSectionGetDof(mesh->coneSection, p, &dof);
1408: PetscSectionGetOffset(mesh->coneSection, p, &off);
1409: 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);
1410: for (c = 0; c < dof; ++c) {
1411: 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);
1412: mesh->cones[off+c] = cone[c];
1413: }
1414: return(0);
1415: }
1417: /*@C
1418: DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1420: Not collective
1422: Input Parameters:
1423: + mesh - The DMPlex
1424: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1426: Output Parameter:
1427: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1428: integer giving the prescription for cone traversal. If it is negative, the cone is
1429: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1430: the index of the cone point on which to start.
1432: Level: beginner
1434: Fortran Notes:
1435: Since it returns an array, this routine is only available in Fortran 90, and you must
1436: include petsc.h90 in your code.
1438: You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1440: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1441: @*/
1442: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1443: {
1444: DM_Plex *mesh = (DM_Plex*) dm->data;
1445: PetscInt off;
1450: #if defined(PETSC_USE_DEBUG)
1451: {
1452: PetscInt dof;
1453: PetscSectionGetDof(mesh->coneSection, p, &dof);
1455: }
1456: #endif
1457: PetscSectionGetOffset(mesh->coneSection, p, &off);
1459: *coneOrientation = &mesh->coneOrientations[off];
1460: return(0);
1461: }
1463: /*@
1464: DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1466: Not collective
1468: Input Parameters:
1469: + mesh - The DMPlex
1470: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1471: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1472: integer giving the prescription for cone traversal. If it is negative, the cone is
1473: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1474: the index of the cone point on which to start.
1476: Output Parameter:
1478: Note:
1479: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1481: Level: beginner
1483: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1484: @*/
1485: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1486: {
1487: DM_Plex *mesh = (DM_Plex*) dm->data;
1488: PetscInt pStart, pEnd;
1489: PetscInt dof, off, c;
1494: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1495: PetscSectionGetDof(mesh->coneSection, p, &dof);
1497: PetscSectionGetOffset(mesh->coneSection, p, &off);
1498: 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);
1499: for (c = 0; c < dof; ++c) {
1500: PetscInt cdof, o = coneOrientation[c];
1502: PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1503: 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);
1504: mesh->coneOrientations[off+c] = o;
1505: }
1506: return(0);
1507: }
1509: /*@
1510: DMPlexInsertCone - Insert a point into the in-edges for the point p in the Sieve DAG
1512: Not collective
1514: Input Parameters:
1515: + mesh - The DMPlex
1516: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1517: . conePos - The local index in the cone where the point should be put
1518: - conePoint - The mesh point to insert
1520: Level: beginner
1522: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1523: @*/
1524: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1525: {
1526: DM_Plex *mesh = (DM_Plex*) dm->data;
1527: PetscInt pStart, pEnd;
1528: PetscInt dof, off;
1533: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1534: 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);
1535: 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);
1536: PetscSectionGetDof(mesh->coneSection, p, &dof);
1537: PetscSectionGetOffset(mesh->coneSection, p, &off);
1538: 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);
1539: mesh->cones[off+conePos] = conePoint;
1540: return(0);
1541: }
1543: /*@
1544: DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the Sieve DAG
1546: Not collective
1548: Input Parameters:
1549: + mesh - The DMPlex
1550: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1551: . conePos - The local index in the cone where the point should be put
1552: - coneOrientation - The point orientation to insert
1554: Level: beginner
1556: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1557: @*/
1558: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1559: {
1560: DM_Plex *mesh = (DM_Plex*) dm->data;
1561: PetscInt pStart, pEnd;
1562: PetscInt dof, off;
1567: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1568: 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);
1569: PetscSectionGetDof(mesh->coneSection, p, &dof);
1570: PetscSectionGetOffset(mesh->coneSection, p, &off);
1571: 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);
1572: mesh->coneOrientations[off+conePos] = coneOrientation;
1573: return(0);
1574: }
1576: /*@
1577: DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1579: Not collective
1581: Input Parameters:
1582: + mesh - The DMPlex
1583: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1585: Output Parameter:
1586: . size - The support size for point p
1588: Level: beginner
1590: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1591: @*/
1592: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1593: {
1594: DM_Plex *mesh = (DM_Plex*) dm->data;
1600: PetscSectionGetDof(mesh->supportSection, p, size);
1601: return(0);
1602: }
1604: /*@
1605: DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1607: Not collective
1609: Input Parameters:
1610: + mesh - The DMPlex
1611: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1612: - size - The support size for point p
1614: Output Parameter:
1616: Note:
1617: This should be called after DMPlexSetChart().
1619: Level: beginner
1621: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1622: @*/
1623: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1624: {
1625: DM_Plex *mesh = (DM_Plex*) dm->data;
1630: PetscSectionSetDof(mesh->supportSection, p, size);
1632: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1633: return(0);
1634: }
1636: /*@C
1637: DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1639: Not collective
1641: Input Parameters:
1642: + mesh - The DMPlex
1643: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1645: Output Parameter:
1646: . support - An array of points which are on the out-edges for point p
1648: Level: beginner
1650: Fortran Notes:
1651: Since it returns an array, this routine is only available in Fortran 90, and you must
1652: include petsc.h90 in your code.
1654: You must also call DMPlexRestoreSupport() after you finish using the returned array.
1656: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1657: @*/
1658: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1659: {
1660: DM_Plex *mesh = (DM_Plex*) dm->data;
1661: PetscInt off;
1667: PetscSectionGetOffset(mesh->supportSection, p, &off);
1668: *support = &mesh->supports[off];
1669: return(0);
1670: }
1672: /*@
1673: DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1675: Not collective
1677: Input Parameters:
1678: + mesh - The DMPlex
1679: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1680: - support - An array of points which are on the in-edges for point p
1682: Output Parameter:
1684: Note:
1685: This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1687: Level: beginner
1689: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1690: @*/
1691: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1692: {
1693: DM_Plex *mesh = (DM_Plex*) dm->data;
1694: PetscInt pStart, pEnd;
1695: PetscInt dof, off, c;
1700: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1701: PetscSectionGetDof(mesh->supportSection, p, &dof);
1703: PetscSectionGetOffset(mesh->supportSection, p, &off);
1704: 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);
1705: for (c = 0; c < dof; ++c) {
1706: 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);
1707: mesh->supports[off+c] = support[c];
1708: }
1709: return(0);
1710: }
1712: /*@
1713: DMPlexInsertSupport - Insert a point into the out-edges for the point p in the Sieve DAG
1715: Not collective
1717: Input Parameters:
1718: + mesh - The DMPlex
1719: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1720: . supportPos - The local index in the cone where the point should be put
1721: - supportPoint - The mesh point to insert
1723: Level: beginner
1725: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1726: @*/
1727: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1728: {
1729: DM_Plex *mesh = (DM_Plex*) dm->data;
1730: PetscInt pStart, pEnd;
1731: PetscInt dof, off;
1736: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1737: PetscSectionGetDof(mesh->supportSection, p, &dof);
1738: PetscSectionGetOffset(mesh->supportSection, p, &off);
1739: 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);
1740: 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);
1741: 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);
1742: mesh->supports[off+supportPos] = supportPoint;
1743: return(0);
1744: }
1746: /*@C
1747: DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1749: Not collective
1751: Input Parameters:
1752: + mesh - The DMPlex
1753: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1754: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
1755: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1757: Output Parameters:
1758: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1759: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1761: Note:
1762: If using internal storage (points is NULL on input), each call overwrites the last output.
1764: Fortran Notes:
1765: Since it returns an array, this routine is only available in Fortran 90, and you must
1766: include petsc.h90 in your code.
1768: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1770: Level: beginner
1772: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1773: @*/
1774: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1775: {
1776: DM_Plex *mesh = (DM_Plex*) dm->data;
1777: PetscInt *closure, *fifo;
1778: const PetscInt *tmp = NULL, *tmpO = NULL;
1779: PetscInt tmpSize, t;
1780: PetscInt depth = 0, maxSize;
1781: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
1782: PetscErrorCode ierr;
1786: DMPlexGetDepth(dm, &depth);
1787: /* This is only 1-level */
1788: if (useCone) {
1789: DMPlexGetConeSize(dm, p, &tmpSize);
1790: DMPlexGetCone(dm, p, &tmp);
1791: DMPlexGetConeOrientation(dm, p, &tmpO);
1792: } else {
1793: DMPlexGetSupportSize(dm, p, &tmpSize);
1794: DMPlexGetSupport(dm, p, &tmp);
1795: }
1796: if (depth == 1) {
1797: if (*points) {
1798: closure = *points;
1799: } else {
1800: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1801: DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1802: }
1803: closure[0] = p; closure[1] = 0;
1804: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1805: closure[closureSize] = tmp[t];
1806: closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1807: }
1808: if (numPoints) *numPoints = closureSize/2;
1809: if (points) *points = closure;
1810: return(0);
1811: }
1812: {
1813: PetscInt c, coneSeries, s,supportSeries;
1815: c = mesh->maxConeSize;
1816: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1817: s = mesh->maxSupportSize;
1818: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1819: maxSize = 2*PetscMax(coneSeries,supportSeries);
1820: }
1821: DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1822: if (*points) {
1823: closure = *points;
1824: } else {
1825: DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1826: }
1827: closure[0] = p; closure[1] = 0;
1828: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1829: const PetscInt cp = tmp[t];
1830: const PetscInt co = tmpO ? tmpO[t] : 0;
1832: closure[closureSize] = cp;
1833: closure[closureSize+1] = co;
1834: fifo[fifoSize] = cp;
1835: fifo[fifoSize+1] = co;
1836: }
1837: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1838: while (fifoSize - fifoStart) {
1839: const PetscInt q = fifo[fifoStart];
1840: const PetscInt o = fifo[fifoStart+1];
1841: const PetscInt rev = o >= 0 ? 0 : 1;
1842: const PetscInt off = rev ? -(o+1) : o;
1844: if (useCone) {
1845: DMPlexGetConeSize(dm, q, &tmpSize);
1846: DMPlexGetCone(dm, q, &tmp);
1847: DMPlexGetConeOrientation(dm, q, &tmpO);
1848: } else {
1849: DMPlexGetSupportSize(dm, q, &tmpSize);
1850: DMPlexGetSupport(dm, q, &tmp);
1851: tmpO = NULL;
1852: }
1853: for (t = 0; t < tmpSize; ++t) {
1854: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
1855: const PetscInt cp = tmp[i];
1856: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1857: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1858: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1859: PetscInt co = tmpO ? tmpO[i] : 0;
1860: PetscInt c;
1862: if (rev) {
1863: PetscInt childSize, coff;
1864: DMPlexGetConeSize(dm, cp, &childSize);
1865: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1866: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1867: }
1868: /* Check for duplicate */
1869: for (c = 0; c < closureSize; c += 2) {
1870: if (closure[c] == cp) break;
1871: }
1872: if (c == closureSize) {
1873: closure[closureSize] = cp;
1874: closure[closureSize+1] = co;
1875: fifo[fifoSize] = cp;
1876: fifo[fifoSize+1] = co;
1877: closureSize += 2;
1878: fifoSize += 2;
1879: }
1880: }
1881: fifoStart += 2;
1882: }
1883: if (numPoints) *numPoints = closureSize/2;
1884: if (points) *points = closure;
1885: DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1886: return(0);
1887: }
1889: /*@C
1890: DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG with a specified initial orientation
1892: Not collective
1894: Input Parameters:
1895: + mesh - The DMPlex
1896: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1897: . orientation - The orientation of the point
1898: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
1899: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1901: Output Parameters:
1902: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1903: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1905: Note:
1906: If using internal storage (points is NULL on input), each call overwrites the last output.
1908: Fortran Notes:
1909: Since it returns an array, this routine is only available in Fortran 90, and you must
1910: include petsc.h90 in your code.
1912: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1914: Level: beginner
1916: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1917: @*/
1918: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1919: {
1920: DM_Plex *mesh = (DM_Plex*) dm->data;
1921: PetscInt *closure, *fifo;
1922: const PetscInt *tmp = NULL, *tmpO = NULL;
1923: PetscInt tmpSize, t;
1924: PetscInt depth = 0, maxSize;
1925: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
1926: PetscErrorCode ierr;
1930: DMPlexGetDepth(dm, &depth);
1931: /* This is only 1-level */
1932: if (useCone) {
1933: DMPlexGetConeSize(dm, p, &tmpSize);
1934: DMPlexGetCone(dm, p, &tmp);
1935: DMPlexGetConeOrientation(dm, p, &tmpO);
1936: } else {
1937: DMPlexGetSupportSize(dm, p, &tmpSize);
1938: DMPlexGetSupport(dm, p, &tmp);
1939: }
1940: if (depth == 1) {
1941: if (*points) {
1942: closure = *points;
1943: } else {
1944: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1945: DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1946: }
1947: closure[0] = p; closure[1] = ornt;
1948: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1949: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1950: closure[closureSize] = tmp[i];
1951: closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1952: }
1953: if (numPoints) *numPoints = closureSize/2;
1954: if (points) *points = closure;
1955: return(0);
1956: }
1957: {
1958: PetscInt c, coneSeries, s,supportSeries;
1960: c = mesh->maxConeSize;
1961: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1962: s = mesh->maxSupportSize;
1963: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1964: maxSize = 2*PetscMax(coneSeries,supportSeries);
1965: }
1966: DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1967: if (*points) {
1968: closure = *points;
1969: } else {
1970: DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1971: }
1972: closure[0] = p; closure[1] = ornt;
1973: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1974: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1975: const PetscInt cp = tmp[i];
1976: PetscInt co = tmpO ? tmpO[i] : 0;
1978: if (ornt < 0) {
1979: PetscInt childSize, coff;
1980: DMPlexGetConeSize(dm, cp, &childSize);
1981: coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
1982: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1983: }
1984: closure[closureSize] = cp;
1985: closure[closureSize+1] = co;
1986: fifo[fifoSize] = cp;
1987: fifo[fifoSize+1] = co;
1988: }
1989: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1990: while (fifoSize - fifoStart) {
1991: const PetscInt q = fifo[fifoStart];
1992: const PetscInt o = fifo[fifoStart+1];
1993: const PetscInt rev = o >= 0 ? 0 : 1;
1994: const PetscInt off = rev ? -(o+1) : o;
1996: if (useCone) {
1997: DMPlexGetConeSize(dm, q, &tmpSize);
1998: DMPlexGetCone(dm, q, &tmp);
1999: DMPlexGetConeOrientation(dm, q, &tmpO);
2000: } else {
2001: DMPlexGetSupportSize(dm, q, &tmpSize);
2002: DMPlexGetSupport(dm, q, &tmp);
2003: tmpO = NULL;
2004: }
2005: for (t = 0; t < tmpSize; ++t) {
2006: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
2007: const PetscInt cp = tmp[i];
2008: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2009: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2010: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2011: PetscInt co = tmpO ? tmpO[i] : 0;
2012: PetscInt c;
2014: if (rev) {
2015: PetscInt childSize, coff;
2016: DMPlexGetConeSize(dm, cp, &childSize);
2017: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2018: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2019: }
2020: /* Check for duplicate */
2021: for (c = 0; c < closureSize; c += 2) {
2022: if (closure[c] == cp) break;
2023: }
2024: if (c == closureSize) {
2025: closure[closureSize] = cp;
2026: closure[closureSize+1] = co;
2027: fifo[fifoSize] = cp;
2028: fifo[fifoSize+1] = co;
2029: closureSize += 2;
2030: fifoSize += 2;
2031: }
2032: }
2033: fifoStart += 2;
2034: }
2035: if (numPoints) *numPoints = closureSize/2;
2036: if (points) *points = closure;
2037: DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
2038: return(0);
2039: }
2041: /*@C
2042: DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
2044: Not collective
2046: Input Parameters:
2047: + mesh - The DMPlex
2048: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
2049: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2050: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
2051: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
2053: Note:
2054: If not using internal storage (points is not NULL on input), this call is unnecessary
2056: Fortran Notes:
2057: Since it returns an array, this routine is only available in Fortran 90, and you must
2058: include petsc.h90 in your code.
2060: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2062: Level: beginner
2064: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2065: @*/
2066: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2067: {
2074: DMRestoreWorkArray(dm, 0, PETSC_INT, points);
2075: if (numPoints) *numPoints = 0;
2076: return(0);
2077: }
2079: /*@
2080: DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
2082: Not collective
2084: Input Parameter:
2085: . mesh - The DMPlex
2087: Output Parameters:
2088: + maxConeSize - The maximum number of in-edges
2089: - maxSupportSize - The maximum number of out-edges
2091: Level: beginner
2093: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2094: @*/
2095: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2096: {
2097: DM_Plex *mesh = (DM_Plex*) dm->data;
2101: if (maxConeSize) *maxConeSize = mesh->maxConeSize;
2102: if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2103: return(0);
2104: }
2106: PetscErrorCode DMSetUp_Plex(DM dm)
2107: {
2108: DM_Plex *mesh = (DM_Plex*) dm->data;
2109: PetscInt size;
2114: PetscSectionSetUp(mesh->coneSection);
2115: PetscSectionGetStorageSize(mesh->coneSection, &size);
2116: PetscMalloc1(size, &mesh->cones);
2117: PetscCalloc1(size, &mesh->coneOrientations);
2118: if (mesh->maxSupportSize) {
2119: PetscSectionSetUp(mesh->supportSection);
2120: PetscSectionGetStorageSize(mesh->supportSection, &size);
2121: PetscMalloc1(size, &mesh->supports);
2122: }
2123: return(0);
2124: }
2126: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
2127: {
2131: if (subdm) {DMClone(dm, subdm);}
2132: DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2133: return(0);
2134: }
2136: /*@
2137: DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
2139: Not collective
2141: Input Parameter:
2142: . mesh - The DMPlex
2144: Output Parameter:
2146: Note:
2147: This should be called after all calls to DMPlexSetCone()
2149: Level: beginner
2151: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2152: @*/
2153: PetscErrorCode DMPlexSymmetrize(DM dm)
2154: {
2155: DM_Plex *mesh = (DM_Plex*) dm->data;
2156: PetscInt *offsets;
2157: PetscInt supportSize;
2158: PetscInt pStart, pEnd, p;
2163: if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2164: /* Calculate support sizes */
2165: DMPlexGetChart(dm, &pStart, &pEnd);
2166: for (p = pStart; p < pEnd; ++p) {
2167: PetscInt dof, off, c;
2169: PetscSectionGetDof(mesh->coneSection, p, &dof);
2170: PetscSectionGetOffset(mesh->coneSection, p, &off);
2171: for (c = off; c < off+dof; ++c) {
2172: PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2173: }
2174: }
2175: for (p = pStart; p < pEnd; ++p) {
2176: PetscInt dof;
2178: PetscSectionGetDof(mesh->supportSection, p, &dof);
2180: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2181: }
2182: PetscSectionSetUp(mesh->supportSection);
2183: /* Calculate supports */
2184: PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2185: PetscMalloc1(supportSize, &mesh->supports);
2186: PetscCalloc1(pEnd - pStart, &offsets);
2187: for (p = pStart; p < pEnd; ++p) {
2188: PetscInt dof, off, c;
2190: PetscSectionGetDof(mesh->coneSection, p, &dof);
2191: PetscSectionGetOffset(mesh->coneSection, p, &off);
2192: for (c = off; c < off+dof; ++c) {
2193: const PetscInt q = mesh->cones[c];
2194: PetscInt offS;
2196: PetscSectionGetOffset(mesh->supportSection, q, &offS);
2198: mesh->supports[offS+offsets[q]] = p;
2199: ++offsets[q];
2200: }
2201: }
2202: PetscFree(offsets);
2203: return(0);
2204: }
2206: /*@
2207: DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2208: can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2209: same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2210: the DAG.
2212: Collective on dm
2214: Input Parameter:
2215: . mesh - The DMPlex
2217: Output Parameter:
2219: Notes:
2220: Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2221: 1 for edges, and so on. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2222: manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed
2223: via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1.
2225: DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
2227: Level: beginner
2229: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2230: @*/
2231: PetscErrorCode DMPlexStratify(DM dm)
2232: {
2233: DM_Plex *mesh = (DM_Plex*) dm->data;
2234: DMLabel label;
2235: PetscInt pStart, pEnd, p;
2236: PetscInt numRoots = 0, numLeaves = 0;
2241: PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2242: /* Calculate depth */
2243: DMPlexGetChart(dm, &pStart, &pEnd);
2244: DMCreateLabel(dm, "depth");
2245: DMPlexGetDepthLabel(dm, &label);
2246: /* Initialize roots and count leaves */
2247: for (p = pStart; p < pEnd; ++p) {
2248: PetscInt coneSize, supportSize;
2250: DMPlexGetConeSize(dm, p, &coneSize);
2251: DMPlexGetSupportSize(dm, p, &supportSize);
2252: if (!coneSize && supportSize) {
2253: ++numRoots;
2254: DMLabelSetValue(label, p, 0);
2255: } else if (!supportSize && coneSize) {
2256: ++numLeaves;
2257: } else if (!supportSize && !coneSize) {
2258: /* Isolated points */
2259: DMLabelSetValue(label, p, 0);
2260: }
2261: }
2262: if (numRoots + numLeaves == (pEnd - pStart)) {
2263: for (p = pStart; p < pEnd; ++p) {
2264: PetscInt coneSize, supportSize;
2266: DMPlexGetConeSize(dm, p, &coneSize);
2267: DMPlexGetSupportSize(dm, p, &supportSize);
2268: if (!supportSize && coneSize) {
2269: DMLabelSetValue(label, p, 1);
2270: }
2271: }
2272: } else {
2273: IS pointIS;
2274: PetscInt numPoints = 0, level = 0;
2276: DMLabelGetStratumIS(label, level, &pointIS);
2277: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2278: while (numPoints) {
2279: const PetscInt *points;
2280: const PetscInt newLevel = level+1;
2282: ISGetIndices(pointIS, &points);
2283: for (p = 0; p < numPoints; ++p) {
2284: const PetscInt point = points[p];
2285: const PetscInt *support;
2286: PetscInt supportSize, s;
2288: DMPlexGetSupportSize(dm, point, &supportSize);
2289: DMPlexGetSupport(dm, point, &support);
2290: for (s = 0; s < supportSize; ++s) {
2291: DMLabelSetValue(label, support[s], newLevel);
2292: }
2293: }
2294: ISRestoreIndices(pointIS, &points);
2295: ++level;
2296: ISDestroy(&pointIS);
2297: DMLabelGetStratumIS(label, level, &pointIS);
2298: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2299: else {numPoints = 0;}
2300: }
2301: ISDestroy(&pointIS);
2302: }
2303: { /* just in case there is an empty process */
2304: PetscInt numValues, maxValues = 0, v;
2306: DMLabelGetNumValues(label,&numValues);
2307: for (v = 0; v < numValues; v++) {
2308: IS pointIS;
2310: DMLabelGetStratumIS(label, v, &pointIS);
2311: if (pointIS) {
2312: PetscInt min, max, numPoints;
2313: PetscInt start;
2314: PetscBool contig;
2316: ISGetLocalSize(pointIS, &numPoints);
2317: ISGetMinMax(pointIS, &min, &max);
2318: ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2319: if (start == 0 && contig) {
2320: ISDestroy(&pointIS);
2321: ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2322: DMLabelSetStratumIS(label, v, pointIS);
2323: }
2324: }
2325: ISDestroy(&pointIS);
2326: }
2327: MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2328: for (v = numValues; v < maxValues; v++) {
2329: DMLabelAddStratum(label,v);
2330: }
2331: }
2333: DMLabelGetState(label, &mesh->depthState);
2334: PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2335: return(0);
2336: }
2338: /*@C
2339: DMPlexGetJoin - Get an array for the join of the set of points
2341: Not Collective
2343: Input Parameters:
2344: + dm - The DMPlex object
2345: . numPoints - The number of input points for the join
2346: - points - The input points
2348: Output Parameters:
2349: + numCoveredPoints - The number of points in the join
2350: - coveredPoints - The points in the join
2352: Level: intermediate
2354: Note: Currently, this is restricted to a single level join
2356: Fortran Notes:
2357: Since it returns an array, this routine is only available in Fortran 90, and you must
2358: include petsc.h90 in your code.
2360: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2362: .keywords: mesh
2363: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2364: @*/
2365: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2366: {
2367: DM_Plex *mesh = (DM_Plex*) dm->data;
2368: PetscInt *join[2];
2369: PetscInt joinSize, i = 0;
2370: PetscInt dof, off, p, c, m;
2378: DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
2379: DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
2380: /* Copy in support of first point */
2381: PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2382: PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2383: for (joinSize = 0; joinSize < dof; ++joinSize) {
2384: join[i][joinSize] = mesh->supports[off+joinSize];
2385: }
2386: /* Check each successive support */
2387: for (p = 1; p < numPoints; ++p) {
2388: PetscInt newJoinSize = 0;
2390: PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2391: PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2392: for (c = 0; c < dof; ++c) {
2393: const PetscInt point = mesh->supports[off+c];
2395: for (m = 0; m < joinSize; ++m) {
2396: if (point == join[i][m]) {
2397: join[1-i][newJoinSize++] = point;
2398: break;
2399: }
2400: }
2401: }
2402: joinSize = newJoinSize;
2403: i = 1-i;
2404: }
2405: *numCoveredPoints = joinSize;
2406: *coveredPoints = join[i];
2407: DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2408: return(0);
2409: }
2411: /*@C
2412: DMPlexRestoreJoin - Restore an array for the join of the set of points
2414: Not Collective
2416: Input Parameters:
2417: + dm - The DMPlex object
2418: . numPoints - The number of input points for the join
2419: - points - The input points
2421: Output Parameters:
2422: + numCoveredPoints - The number of points in the join
2423: - coveredPoints - The points in the join
2425: Fortran Notes:
2426: Since it returns an array, this routine is only available in Fortran 90, and you must
2427: include petsc.h90 in your code.
2429: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2431: Level: intermediate
2433: .keywords: mesh
2434: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2435: @*/
2436: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2437: {
2445: DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2446: if (numCoveredPoints) *numCoveredPoints = 0;
2447: return(0);
2448: }
2450: /*@C
2451: DMPlexGetFullJoin - Get an array for the join of the set of points
2453: Not Collective
2455: Input Parameters:
2456: + dm - The DMPlex object
2457: . numPoints - The number of input points for the join
2458: - points - The input points
2460: Output Parameters:
2461: + numCoveredPoints - The number of points in the join
2462: - coveredPoints - The points in the join
2464: Fortran Notes:
2465: Since it returns an array, this routine is only available in Fortran 90, and you must
2466: include petsc.h90 in your code.
2468: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2470: Level: intermediate
2472: .keywords: mesh
2473: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2474: @*/
2475: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2476: {
2477: DM_Plex *mesh = (DM_Plex*) dm->data;
2478: PetscInt *offsets, **closures;
2479: PetscInt *join[2];
2480: PetscInt depth = 0, maxSize, joinSize = 0, i = 0;
2481: PetscInt p, d, c, m, ms;
2490: DMPlexGetDepth(dm, &depth);
2491: PetscCalloc1(numPoints, &closures);
2492: DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2493: ms = mesh->maxSupportSize;
2494: maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2495: DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
2496: DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);
2498: for (p = 0; p < numPoints; ++p) {
2499: PetscInt closureSize;
2501: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);
2503: offsets[p*(depth+2)+0] = 0;
2504: for (d = 0; d < depth+1; ++d) {
2505: PetscInt pStart, pEnd, i;
2507: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2508: for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2509: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2510: offsets[p*(depth+2)+d+1] = i;
2511: break;
2512: }
2513: }
2514: if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2515: }
2516: 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);
2517: }
2518: for (d = 0; d < depth+1; ++d) {
2519: PetscInt dof;
2521: /* Copy in support of first point */
2522: dof = offsets[d+1] - offsets[d];
2523: for (joinSize = 0; joinSize < dof; ++joinSize) {
2524: join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2525: }
2526: /* Check each successive cone */
2527: for (p = 1; p < numPoints && joinSize; ++p) {
2528: PetscInt newJoinSize = 0;
2530: dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2531: for (c = 0; c < dof; ++c) {
2532: const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2534: for (m = 0; m < joinSize; ++m) {
2535: if (point == join[i][m]) {
2536: join[1-i][newJoinSize++] = point;
2537: break;
2538: }
2539: }
2540: }
2541: joinSize = newJoinSize;
2542: i = 1-i;
2543: }
2544: if (joinSize) break;
2545: }
2546: *numCoveredPoints = joinSize;
2547: *coveredPoints = join[i];
2548: for (p = 0; p < numPoints; ++p) {
2549: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2550: }
2551: PetscFree(closures);
2552: DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2553: DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2554: return(0);
2555: }
2557: /*@C
2558: DMPlexGetMeet - Get an array for the meet of the set of points
2560: Not Collective
2562: Input Parameters:
2563: + dm - The DMPlex object
2564: . numPoints - The number of input points for the meet
2565: - points - The input points
2567: Output Parameters:
2568: + numCoveredPoints - The number of points in the meet
2569: - coveredPoints - The points in the meet
2571: Level: intermediate
2573: Note: Currently, this is restricted to a single level meet
2575: Fortran Notes:
2576: Since it returns an array, this routine is only available in Fortran 90, and you must
2577: include petsc.h90 in your code.
2579: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2581: .keywords: mesh
2582: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2583: @*/
2584: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2585: {
2586: DM_Plex *mesh = (DM_Plex*) dm->data;
2587: PetscInt *meet[2];
2588: PetscInt meetSize, i = 0;
2589: PetscInt dof, off, p, c, m;
2597: DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
2598: DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
2599: /* Copy in cone of first point */
2600: PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2601: PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2602: for (meetSize = 0; meetSize < dof; ++meetSize) {
2603: meet[i][meetSize] = mesh->cones[off+meetSize];
2604: }
2605: /* Check each successive cone */
2606: for (p = 1; p < numPoints; ++p) {
2607: PetscInt newMeetSize = 0;
2609: PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2610: PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2611: for (c = 0; c < dof; ++c) {
2612: const PetscInt point = mesh->cones[off+c];
2614: for (m = 0; m < meetSize; ++m) {
2615: if (point == meet[i][m]) {
2616: meet[1-i][newMeetSize++] = point;
2617: break;
2618: }
2619: }
2620: }
2621: meetSize = newMeetSize;
2622: i = 1-i;
2623: }
2624: *numCoveringPoints = meetSize;
2625: *coveringPoints = meet[i];
2626: DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2627: return(0);
2628: }
2630: /*@C
2631: DMPlexRestoreMeet - Restore an array for the meet of the set of points
2633: Not Collective
2635: Input Parameters:
2636: + dm - The DMPlex object
2637: . numPoints - The number of input points for the meet
2638: - points - The input points
2640: Output Parameters:
2641: + numCoveredPoints - The number of points in the meet
2642: - coveredPoints - The points in the meet
2644: Level: intermediate
2646: Fortran Notes:
2647: Since it returns an array, this routine is only available in Fortran 90, and you must
2648: include petsc.h90 in your code.
2650: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2652: .keywords: mesh
2653: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2654: @*/
2655: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2656: {
2664: DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2665: if (numCoveredPoints) *numCoveredPoints = 0;
2666: return(0);
2667: }
2669: /*@C
2670: DMPlexGetFullMeet - Get an array for the meet of the set of points
2672: Not Collective
2674: Input Parameters:
2675: + dm - The DMPlex object
2676: . numPoints - The number of input points for the meet
2677: - points - The input points
2679: Output Parameters:
2680: + numCoveredPoints - The number of points in the meet
2681: - coveredPoints - The points in the meet
2683: Level: intermediate
2685: Fortran Notes:
2686: Since it returns an array, this routine is only available in Fortran 90, and you must
2687: include petsc.h90 in your code.
2689: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2691: .keywords: mesh
2692: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2693: @*/
2694: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2695: {
2696: DM_Plex *mesh = (DM_Plex*) dm->data;
2697: PetscInt *offsets, **closures;
2698: PetscInt *meet[2];
2699: PetscInt height = 0, maxSize, meetSize = 0, i = 0;
2700: PetscInt p, h, c, m, mc;
2709: DMPlexGetDepth(dm, &height);
2710: PetscMalloc1(numPoints, &closures);
2711: DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2712: mc = mesh->maxConeSize;
2713: maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2714: DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
2715: DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);
2717: for (p = 0; p < numPoints; ++p) {
2718: PetscInt closureSize;
2720: DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);
2722: offsets[p*(height+2)+0] = 0;
2723: for (h = 0; h < height+1; ++h) {
2724: PetscInt pStart, pEnd, i;
2726: DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2727: for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2728: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2729: offsets[p*(height+2)+h+1] = i;
2730: break;
2731: }
2732: }
2733: if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2734: }
2735: 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);
2736: }
2737: for (h = 0; h < height+1; ++h) {
2738: PetscInt dof;
2740: /* Copy in cone of first point */
2741: dof = offsets[h+1] - offsets[h];
2742: for (meetSize = 0; meetSize < dof; ++meetSize) {
2743: meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2744: }
2745: /* Check each successive cone */
2746: for (p = 1; p < numPoints && meetSize; ++p) {
2747: PetscInt newMeetSize = 0;
2749: dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2750: for (c = 0; c < dof; ++c) {
2751: const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2753: for (m = 0; m < meetSize; ++m) {
2754: if (point == meet[i][m]) {
2755: meet[1-i][newMeetSize++] = point;
2756: break;
2757: }
2758: }
2759: }
2760: meetSize = newMeetSize;
2761: i = 1-i;
2762: }
2763: if (meetSize) break;
2764: }
2765: *numCoveredPoints = meetSize;
2766: *coveredPoints = meet[i];
2767: for (p = 0; p < numPoints; ++p) {
2768: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2769: }
2770: PetscFree(closures);
2771: DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2772: DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2773: return(0);
2774: }
2776: /*@C
2777: DMPlexEqual - Determine if two DMs have the same topology
2779: Not Collective
2781: Input Parameters:
2782: + dmA - A DMPlex object
2783: - dmB - A DMPlex object
2785: Output Parameters:
2786: . equal - PETSC_TRUE if the topologies are identical
2788: Level: intermediate
2790: Notes:
2791: We are not solving graph isomorphism, so we do not permutation.
2793: .keywords: mesh
2794: .seealso: DMPlexGetCone()
2795: @*/
2796: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2797: {
2798: PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
2806: *equal = PETSC_FALSE;
2807: DMPlexGetDepth(dmA, &depth);
2808: DMPlexGetDepth(dmB, &depthB);
2809: if (depth != depthB) return(0);
2810: DMPlexGetChart(dmA, &pStart, &pEnd);
2811: DMPlexGetChart(dmB, &pStartB, &pEndB);
2812: if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2813: for (p = pStart; p < pEnd; ++p) {
2814: const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2815: PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s;
2817: DMPlexGetConeSize(dmA, p, &coneSize);
2818: DMPlexGetCone(dmA, p, &cone);
2819: DMPlexGetConeOrientation(dmA, p, &ornt);
2820: DMPlexGetConeSize(dmB, p, &coneSizeB);
2821: DMPlexGetCone(dmB, p, &coneB);
2822: DMPlexGetConeOrientation(dmB, p, &orntB);
2823: if (coneSize != coneSizeB) return(0);
2824: for (c = 0; c < coneSize; ++c) {
2825: if (cone[c] != coneB[c]) return(0);
2826: if (ornt[c] != orntB[c]) return(0);
2827: }
2828: DMPlexGetSupportSize(dmA, p, &supportSize);
2829: DMPlexGetSupport(dmA, p, &support);
2830: DMPlexGetSupportSize(dmB, p, &supportSizeB);
2831: DMPlexGetSupport(dmB, p, &supportB);
2832: if (supportSize != supportSizeB) return(0);
2833: for (s = 0; s < supportSize; ++s) {
2834: if (support[s] != supportB[s]) return(0);
2835: }
2836: }
2837: *equal = PETSC_TRUE;
2838: return(0);
2839: }
2841: /*@C
2842: DMPlexGetNumFaceVertices - Returns the number of vertices on a face
2844: Not Collective
2846: Input Parameters:
2847: + dm - The DMPlex
2848: . cellDim - The cell dimension
2849: - numCorners - The number of vertices on a cell
2851: Output Parameters:
2852: . numFaceVertices - The number of vertices on a face
2854: Level: developer
2856: Notes:
2857: Of course this can only work for a restricted set of symmetric shapes
2859: .seealso: DMPlexGetCone()
2860: @*/
2861: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2862: {
2863: MPI_Comm comm;
2867: PetscObjectGetComm((PetscObject)dm,&comm);
2869: switch (cellDim) {
2870: case 0:
2871: *numFaceVertices = 0;
2872: break;
2873: case 1:
2874: *numFaceVertices = 1;
2875: break;
2876: case 2:
2877: switch (numCorners) {
2878: case 3: /* triangle */
2879: *numFaceVertices = 2; /* Edge has 2 vertices */
2880: break;
2881: case 4: /* quadrilateral */
2882: *numFaceVertices = 2; /* Edge has 2 vertices */
2883: break;
2884: case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2885: *numFaceVertices = 3; /* Edge has 3 vertices */
2886: break;
2887: case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2888: *numFaceVertices = 3; /* Edge has 3 vertices */
2889: break;
2890: default:
2891: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2892: }
2893: break;
2894: case 3:
2895: switch (numCorners) {
2896: case 4: /* tetradehdron */
2897: *numFaceVertices = 3; /* Face has 3 vertices */
2898: break;
2899: case 6: /* tet cohesive cells */
2900: *numFaceVertices = 4; /* Face has 4 vertices */
2901: break;
2902: case 8: /* hexahedron */
2903: *numFaceVertices = 4; /* Face has 4 vertices */
2904: break;
2905: case 9: /* tet cohesive Lagrange cells */
2906: *numFaceVertices = 6; /* Face has 6 vertices */
2907: break;
2908: case 10: /* quadratic tetrahedron */
2909: *numFaceVertices = 6; /* Face has 6 vertices */
2910: break;
2911: case 12: /* hex cohesive Lagrange cells */
2912: *numFaceVertices = 6; /* Face has 6 vertices */
2913: break;
2914: case 18: /* quadratic tet cohesive Lagrange cells */
2915: *numFaceVertices = 6; /* Face has 6 vertices */
2916: break;
2917: case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2918: *numFaceVertices = 9; /* Face has 9 vertices */
2919: break;
2920: default:
2921: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2922: }
2923: break;
2924: default:
2925: SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
2926: }
2927: return(0);
2928: }
2930: /*@
2931: DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
2933: Not Collective
2935: Input Parameter:
2936: . dm - The DMPlex object
2938: Output Parameter:
2939: . depthLabel - The DMLabel recording point depth
2941: Level: developer
2943: .keywords: mesh, points
2944: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2945: @*/
2946: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2947: {
2953: if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
2954: *depthLabel = dm->depthLabel;
2955: return(0);
2956: }
2958: /*@
2959: DMPlexGetDepth - Get the depth of the DAG representing this mesh
2961: Not Collective
2963: Input Parameter:
2964: . dm - The DMPlex object
2966: Output Parameter:
2967: . depth - The number of strata (breadth first levels) in the DAG
2969: Level: developer
2971: .keywords: mesh, points
2972: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2973: @*/
2974: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
2975: {
2976: DMLabel label;
2977: PetscInt d = 0;
2983: DMPlexGetDepthLabel(dm, &label);
2984: if (label) {DMLabelGetNumValues(label, &d);}
2985: *depth = d-1;
2986: return(0);
2987: }
2989: /*@
2990: DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
2992: Not Collective
2994: Input Parameters:
2995: + dm - The DMPlex object
2996: - stratumValue - The requested depth
2998: Output Parameters:
2999: + start - The first point at this depth
3000: - end - One beyond the last point at this depth
3002: Level: developer
3004: .keywords: mesh, points
3005: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3006: @*/
3007: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3008: {
3009: DMLabel label;
3010: PetscInt pStart, pEnd;
3017: DMPlexGetChart(dm, &pStart, &pEnd);
3018: if (pStart == pEnd) return(0);
3019: if (stratumValue < 0) {
3020: if (start) *start = pStart;
3021: if (end) *end = pEnd;
3022: return(0);
3023: }
3024: DMPlexGetDepthLabel(dm, &label);
3025: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3026: DMLabelGetStratumBounds(label, stratumValue, start, end);
3027: return(0);
3028: }
3030: /*@
3031: DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3033: Not Collective
3035: Input Parameters:
3036: + dm - The DMPlex object
3037: - stratumValue - The requested height
3039: Output Parameters:
3040: + start - The first point at this height
3041: - end - One beyond the last point at this height
3043: Level: developer
3045: .keywords: mesh, points
3046: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3047: @*/
3048: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3049: {
3050: DMLabel label;
3051: PetscInt depth, pStart, pEnd;
3058: DMPlexGetChart(dm, &pStart, &pEnd);
3059: if (pStart == pEnd) return(0);
3060: if (stratumValue < 0) {
3061: if (start) *start = pStart;
3062: if (end) *end = pEnd;
3063: return(0);
3064: }
3065: DMPlexGetDepthLabel(dm, &label);
3066: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3067: DMLabelGetNumValues(label, &depth);
3068: DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3069: return(0);
3070: }
3072: /* Set the number of dof on each point and separate by fields */
3073: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3074: {
3075: PetscInt *pMax;
3076: PetscInt depth, pStart = 0, pEnd = 0;
3077: PetscInt Nf, p, d, dep, f;
3078: PetscBool *isFE;
3082: PetscMalloc1(numFields, &isFE);
3083: DMGetNumFields(dm, &Nf);
3084: for (f = 0; f < numFields; ++f) {
3085: PetscObject obj;
3086: PetscClassId id;
3088: isFE[f] = PETSC_FALSE;
3089: if (f >= Nf) continue;
3090: DMGetField(dm, f, &obj);
3091: PetscObjectGetClassId(obj, &id);
3092: if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;}
3093: else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3094: }
3095: PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
3096: if (numFields > 0) {
3097: PetscSectionSetNumFields(*section, numFields);
3098: if (numComp) {
3099: for (f = 0; f < numFields; ++f) {
3100: PetscSectionSetFieldComponents(*section, f, numComp[f]);
3101: if (isFE[f]) {
3102: PetscFE fe;
3103: PetscDualSpace dspace;
3104: const PetscInt ***perms;
3105: const PetscScalar ***flips;
3106: const PetscInt *numDof;
3108: DMGetField(dm,f,(PetscObject *) &fe);
3109: PetscFEGetDualSpace(fe,&dspace);
3110: PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3111: PetscDualSpaceGetNumDof(dspace,&numDof);
3112: if (perms || flips) {
3113: DM K;
3114: DMLabel depthLabel;
3115: PetscInt depth, h;
3116: PetscSectionSym sym;
3118: PetscDualSpaceGetDM(dspace,&K);
3119: DMPlexGetDepthLabel(dm,&depthLabel);
3120: DMPlexGetDepth(dm,&depth);
3121: PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
3122: for (h = 0; h <= depth; h++) {
3123: PetscDualSpace hspace;
3124: PetscInt kStart, kEnd;
3125: PetscInt kConeSize;
3126: const PetscInt **perms0 = NULL;
3127: const PetscScalar **flips0 = NULL;
3129: PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3130: DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3131: if (!hspace) continue;
3132: PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3133: if (perms) perms0 = perms[0];
3134: if (flips) flips0 = flips[0];
3135: if (!(perms0 || flips0)) continue;
3136: DMPlexGetConeSize(K,kStart,&kConeSize);
3137: PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3138: }
3139: PetscSectionSetFieldSym(*section,f,sym);
3140: PetscSectionSymDestroy(&sym);
3141: }
3142: }
3143: }
3144: }
3145: }
3146: DMPlexGetChart(dm, &pStart, &pEnd);
3147: PetscSectionSetChart(*section, pStart, pEnd);
3148: DMPlexGetDepth(dm, &depth);
3149: PetscMalloc1(depth+1,&pMax);
3150: DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3151: for (dep = 0; dep <= depth; ++dep) {
3152: d = dim == depth ? dep : (!dep ? 0 : dim);
3153: DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3154: pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3155: for (p = pStart; p < pEnd; ++p) {
3156: PetscInt tot = 0;
3158: for (f = 0; f < numFields; ++f) {
3159: if (isFE[f] && p >= pMax[dep]) continue;
3160: PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3161: tot += numDof[f*(dim+1)+d];
3162: }
3163: PetscSectionSetDof(*section, p, tot);
3164: }
3165: }
3166: PetscFree(pMax);
3167: PetscFree(isFE);
3168: return(0);
3169: }
3171: /* Set the number of dof on each point and separate by fields
3172: If bcComps is NULL or the IS is NULL, constrain every dof on the point
3173: */
3174: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3175: {
3176: PetscInt numFields;
3177: PetscInt bc;
3178: PetscSection aSec;
3182: PetscSectionGetNumFields(section, &numFields);
3183: for (bc = 0; bc < numBC; ++bc) {
3184: PetscInt field = 0;
3185: const PetscInt *comp;
3186: const PetscInt *idx;
3187: PetscInt Nc = -1, n, i;
3189: if (numFields) field = bcField[bc];
3190: if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3191: if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3192: ISGetLocalSize(bcPoints[bc], &n);
3193: ISGetIndices(bcPoints[bc], &idx);
3194: for (i = 0; i < n; ++i) {
3195: const PetscInt p = idx[i];
3196: PetscInt numConst;
3198: if (numFields) {
3199: PetscSectionGetFieldDof(section, p, field, &numConst);
3200: } else {
3201: PetscSectionGetDof(section, p, &numConst);
3202: }
3203: /* If Nc < 0, constrain every dof on the point */
3204: if (Nc > 0) numConst = PetscMin(numConst, Nc);
3205: if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3206: PetscSectionAddConstraintDof(section, p, numConst);
3207: }
3208: ISRestoreIndices(bcPoints[bc], &idx);
3209: if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3210: }
3211: DMPlexGetAnchors(dm, &aSec, NULL);
3212: if (aSec) {
3213: PetscInt aStart, aEnd, a;
3215: PetscSectionGetChart(aSec, &aStart, &aEnd);
3216: for (a = aStart; a < aEnd; a++) {
3217: PetscInt dof, f;
3219: PetscSectionGetDof(aSec, a, &dof);
3220: if (dof) {
3221: /* if there are point-to-point constraints, then all dofs are constrained */
3222: PetscSectionGetDof(section, a, &dof);
3223: PetscSectionSetConstraintDof(section, a, dof);
3224: for (f = 0; f < numFields; f++) {
3225: PetscSectionGetFieldDof(section, a, f, &dof);
3226: PetscSectionSetFieldConstraintDof(section, a, f, dof);
3227: }
3228: }
3229: }
3230: }
3231: return(0);
3232: }
3234: /* Set the constrained field indices on each point
3235: If bcComps is NULL or the IS is NULL, constrain every dof on the point
3236: */
3237: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3238: {
3239: PetscSection aSec;
3240: PetscInt *indices;
3241: PetscInt numFields, cdof, maxDof = 0, pStart, pEnd, p, bc, f, d;
3245: PetscSectionGetNumFields(section, &numFields);
3246: if (!numFields) return(0);
3247: /* Initialize all field indices to -1 */
3248: PetscSectionGetChart(section, &pStart, &pEnd);
3249: for (p = pStart; p < pEnd; ++p) {PetscSectionGetConstraintDof(section, p, &cdof); maxDof = PetscMax(maxDof, cdof);}
3250: PetscMalloc1(maxDof, &indices);
3251: for (d = 0; d < maxDof; ++d) indices[d] = -1;
3252: for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3253: /* Handle BC constraints */
3254: for (bc = 0; bc < numBC; ++bc) {
3255: const PetscInt field = bcField[bc];
3256: const PetscInt *comp, *idx;
3257: PetscInt Nc = -1, n, i;
3259: if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3260: if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3261: ISGetLocalSize(bcPoints[bc], &n);
3262: ISGetIndices(bcPoints[bc], &idx);
3263: for (i = 0; i < n; ++i) {
3264: const PetscInt p = idx[i];
3265: const PetscInt *find;
3266: PetscInt fdof, fcdof, c;
3268: PetscSectionGetFieldDof(section, p, field, &fdof);
3269: if (!fdof) continue;
3270: if (Nc < 0) {
3271: for (d = 0; d < fdof; ++d) indices[d] = d;
3272: fcdof = fdof;
3273: } else {
3274: PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3275: PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3276: for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3277: for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
3278: PetscSortRemoveDupsInt(&d, indices);
3279: for (c = d; c < fcdof; ++c) indices[c] = -1;
3280: fcdof = d;
3281: }
3282: PetscSectionSetFieldConstraintDof(section, p, field, fcdof);
3283: PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3284: }
3285: if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3286: ISRestoreIndices(bcPoints[bc], &idx);
3287: }
3288: /* Handle anchors */
3289: DMPlexGetAnchors(dm, &aSec, NULL);
3290: if (aSec) {
3291: PetscInt aStart, aEnd, a;
3293: for (d = 0; d < maxDof; ++d) indices[d] = d;
3294: PetscSectionGetChart(aSec, &aStart, &aEnd);
3295: for (a = aStart; a < aEnd; a++) {
3296: PetscInt dof, f;
3298: PetscSectionGetDof(aSec, a, &dof);
3299: if (dof) {
3300: /* if there are point-to-point constraints, then all dofs are constrained */
3301: for (f = 0; f < numFields; f++) {
3302: PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3303: }
3304: }
3305: }
3306: }
3307: PetscFree(indices);
3308: return(0);
3309: }
3311: /* Set the constrained indices on each point */
3312: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3313: {
3314: PetscInt *indices;
3315: PetscInt numFields, maxDof, pStart, pEnd, p, f, d;
3319: PetscSectionGetNumFields(section, &numFields);
3320: PetscSectionGetMaxDof(section, &maxDof);
3321: PetscSectionGetChart(section, &pStart, &pEnd);
3322: PetscMalloc1(maxDof, &indices);
3323: for (d = 0; d < maxDof; ++d) indices[d] = -1;
3324: for (p = pStart; p < pEnd; ++p) {
3325: PetscInt cdof, d;
3327: PetscSectionGetConstraintDof(section, p, &cdof);
3328: if (cdof) {
3329: if (numFields) {
3330: PetscInt numConst = 0, foff = 0;
3332: for (f = 0; f < numFields; ++f) {
3333: const PetscInt *find;
3334: PetscInt fcdof, fdof;
3336: PetscSectionGetFieldDof(section, p, f, &fdof);
3337: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3338: /* Change constraint numbering from field component to local dof number */
3339: PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3340: for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3341: numConst += fcdof;
3342: foff += fdof;
3343: }
3344: if (cdof != numConst) {PetscSectionSetConstraintDof(section, p, numConst);}
3345: } else {
3346: for (d = 0; d < cdof; ++d) indices[d] = d;
3347: }
3348: PetscSectionSetConstraintIndices(section, p, indices);
3349: }
3350: }
3351: PetscFree(indices);
3352: return(0);
3353: }
3355: /*@C
3356: DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
3358: Not Collective
3360: Input Parameters:
3361: + dm - The DMPlex object
3362: . dim - The spatial dimension of the problem
3363: . numFields - The number of fields in the problem
3364: . numComp - An array of size numFields that holds the number of components for each field
3365: . numDof - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3366: . numBC - The number of boundary conditions
3367: . bcField - An array of size numBC giving the field number for each boundry condition
3368: . bcComps - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3369: . bcPoints - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3370: - perm - Optional permutation of the chart, or NULL
3372: Output Parameter:
3373: . section - The PetscSection object
3375: Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the
3376: number of dof for field 0 on each edge.
3378: The chart permutation is the same one set using PetscSectionSetPermutation()
3380: Level: developer
3382: Fortran Notes:
3383: A Fortran 90 version is available as DMPlexCreateSectionF90()
3385: .keywords: mesh, elements
3386: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3387: @*/
3388: PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], IS perm, PetscSection *section)
3389: {
3390: PetscSection aSec;
3394: DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3395: DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3396: if (perm) {PetscSectionSetPermutation(*section, perm);}
3397: PetscSectionSetUp(*section);
3398: DMPlexGetAnchors(dm,&aSec,NULL);
3399: if (numBC || aSec) {
3400: DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3401: DMPlexCreateSectionBCIndices(dm, *section);
3402: }
3403: PetscSectionViewFromOptions(*section,NULL,"-section_view");
3404: return(0);
3405: }
3407: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3408: {
3409: PetscSection section, s;
3410: Mat m;
3411: PetscInt maxHeight;
3415: DMClone(dm, cdm);
3416: DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3417: DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3418: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
3419: DMSetDefaultSection(*cdm, section);
3420: PetscSectionDestroy(§ion);
3421: PetscSectionCreate(PETSC_COMM_SELF, &s);
3422: MatCreate(PETSC_COMM_SELF, &m);
3423: DMSetDefaultConstraints(*cdm, s, m);
3424: PetscSectionDestroy(&s);
3425: MatDestroy(&m);
3426: return(0);
3427: }
3429: /*@C
3430: DMPlexGetConeSection - Return a section which describes the layout of cone data
3432: Not Collective
3434: Input Parameters:
3435: . dm - The DMPlex object
3437: Output Parameter:
3438: . section - The PetscSection object
3440: Level: developer
3442: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3443: @*/
3444: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3445: {
3446: DM_Plex *mesh = (DM_Plex*) dm->data;
3450: if (section) *section = mesh->coneSection;
3451: return(0);
3452: }
3454: /*@C
3455: DMPlexGetSupportSection - Return a section which describes the layout of support data
3457: Not Collective
3459: Input Parameters:
3460: . dm - The DMPlex object
3462: Output Parameter:
3463: . section - The PetscSection object
3465: Level: developer
3467: .seealso: DMPlexGetConeSection()
3468: @*/
3469: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3470: {
3471: DM_Plex *mesh = (DM_Plex*) dm->data;
3475: if (section) *section = mesh->supportSection;
3476: return(0);
3477: }
3479: /*@C
3480: DMPlexGetCones - Return cone data
3482: Not Collective
3484: Input Parameters:
3485: . dm - The DMPlex object
3487: Output Parameter:
3488: . cones - The cone for each point
3490: Level: developer
3492: .seealso: DMPlexGetConeSection()
3493: @*/
3494: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3495: {
3496: DM_Plex *mesh = (DM_Plex*) dm->data;
3500: if (cones) *cones = mesh->cones;
3501: return(0);
3502: }
3504: /*@C
3505: DMPlexGetConeOrientations - Return cone orientation data
3507: Not Collective
3509: Input Parameters:
3510: . dm - The DMPlex object
3512: Output Parameter:
3513: . coneOrientations - The cone orientation for each point
3515: Level: developer
3517: .seealso: DMPlexGetConeSection()
3518: @*/
3519: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3520: {
3521: DM_Plex *mesh = (DM_Plex*) dm->data;
3525: if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3526: return(0);
3527: }
3529: /******************************** FEM Support **********************************/
3531: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3532: {
3533: PetscInt *perm;
3534: PetscInt dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3538: if (!section) {DMGetDefaultSection(dm, §ion);}
3539: DMGetDimension(dm, &dim);
3540: PetscSectionGetNumFields(section, &Nf);
3541: if (dim <= 1) return(0);
3542: for (f = 0; f < Nf; ++f) {
3543: /* An order k SEM disc has k-1 dofs on an edge */
3544: DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3545: PetscSectionGetFieldDof(section, eStart, f, &k);
3546: PetscSectionGetFieldComponents(section, f, &Nc);
3547: k = k/Nc + 1;
3548: size += PetscPowInt(k+1, dim)*Nc;
3549: }
3550: PetscMalloc1(size, &perm);
3551: for (f = 0; f < Nf; ++f) {
3552: switch (dim) {
3553: case 2:
3554: /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3555: DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3556: PetscSectionGetFieldDof(section, eStart, f, &k);
3557: PetscSectionGetFieldComponents(section, f, &Nc);
3558: k = k/Nc + 1;
3559: /* The SEM order is
3561: v_lb, {e_b}, v_rb,
3562: e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3563: v_lt, reverse {e_t}, v_rt
3564: */
3565: {
3566: const PetscInt of = 0;
3567: const PetscInt oeb = of + PetscSqr(k-1);
3568: const PetscInt oer = oeb + (k-1);
3569: const PetscInt oet = oer + (k-1);
3570: const PetscInt oel = oet + (k-1);
3571: const PetscInt ovlb = oel + (k-1);
3572: const PetscInt ovrb = ovlb + 1;
3573: const PetscInt ovrt = ovrb + 1;
3574: const PetscInt ovlt = ovrt + 1;
3575: PetscInt o;
3577: /* bottom */
3578: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3579: for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3580: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3581: /* middle */
3582: for (i = 0; i < k-1; ++i) {
3583: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3584: 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;
3585: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3586: }
3587: /* top */
3588: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3589: for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3590: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3591: foffset = offset;
3592: }
3593: break;
3594: case 3:
3595: /* The original hex closure is
3597: {c,
3598: f_b, f_t, f_f, f_b, f_r, f_l,
3599: e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb,
3600: v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3601: */
3602: DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3603: PetscSectionGetFieldDof(section, eStart, f, &k);
3604: PetscSectionGetFieldComponents(section, f, &Nc);
3605: k = k/Nc + 1;
3606: /* The SEM order is
3607: Bottom Slice
3608: v_blf, {e^{(k-1)-n}_bf}, v_brf,
3609: e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3610: v_blb, {e_bb}, v_brb,
3612: Middle Slice (j)
3613: {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3614: f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3615: e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3617: Top Slice
3618: v_tlf, {e_tf}, v_trf,
3619: e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3620: v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3621: */
3622: {
3623: const PetscInt oc = 0;
3624: const PetscInt ofb = oc + PetscSqr(k-1)*(k-1);
3625: const PetscInt oft = ofb + PetscSqr(k-1);
3626: const PetscInt off = oft + PetscSqr(k-1);
3627: const PetscInt ofk = off + PetscSqr(k-1);
3628: const PetscInt ofr = ofk + PetscSqr(k-1);
3629: const PetscInt ofl = ofr + PetscSqr(k-1);
3630: const PetscInt oebl = ofl + PetscSqr(k-1);
3631: const PetscInt oebb = oebl + (k-1);
3632: const PetscInt oebr = oebb + (k-1);
3633: const PetscInt oebf = oebr + (k-1);
3634: const PetscInt oetf = oebf + (k-1);
3635: const PetscInt oetr = oetf + (k-1);
3636: const PetscInt oetb = oetr + (k-1);
3637: const PetscInt oetl = oetb + (k-1);
3638: const PetscInt oerf = oetl + (k-1);
3639: const PetscInt oelf = oerf + (k-1);
3640: const PetscInt oelb = oelf + (k-1);
3641: const PetscInt oerb = oelb + (k-1);
3642: const PetscInt ovblf = oerb + (k-1);
3643: const PetscInt ovblb = ovblf + 1;
3644: const PetscInt ovbrb = ovblb + 1;
3645: const PetscInt ovbrf = ovbrb + 1;
3646: const PetscInt ovtlf = ovbrf + 1;
3647: const PetscInt ovtrf = ovtlf + 1;
3648: const PetscInt ovtrb = ovtrf + 1;
3649: const PetscInt ovtlb = ovtrb + 1;
3650: PetscInt o, n;
3652: /* Bottom Slice */
3653: /* bottom */
3654: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3655: for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3656: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3657: /* middle */
3658: for (i = 0; i < k-1; ++i) {
3659: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3660: 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;}
3661: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3662: }
3663: /* top */
3664: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3665: for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3666: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
3668: /* Middle Slice */
3669: for (j = 0; j < k-1; ++j) {
3670: /* bottom */
3671: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3672: 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;
3673: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3674: /* middle */
3675: for (i = 0; i < k-1; ++i) {
3676: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3677: 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;
3678: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3679: }
3680: /* top */
3681: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3682: 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;
3683: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3684: }
3686: /* Top Slice */
3687: /* bottom */
3688: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3689: for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3690: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3691: /* middle */
3692: for (i = 0; i < k-1; ++i) {
3693: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3694: for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3695: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3696: }
3697: /* top */
3698: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3699: for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3700: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
3702: foffset = offset;
3703: }
3704: break;
3705: default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3706: }
3707: }
3708: if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3709: /* Check permutation */
3710: {
3711: PetscInt *check;
3713: PetscMalloc1(size, &check);
3714: 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]);}
3715: for (i = 0; i < size; ++i) check[perm[i]] = i;
3716: for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3717: PetscFree(check);
3718: }
3719: PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3720: return(0);
3721: }
3723: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3724: {
3725: PetscDS prob;
3726: PetscInt depth, Nf, h;
3727: DMLabel label;
3731: prob = dm->prob;
3732: Nf = prob->Nf;
3733: label = dm->depthLabel;
3734: *dspace = NULL;
3735: if (field < Nf) {
3736: PetscObject disc = prob->disc[field];
3738: if (disc->classid == PETSCFE_CLASSID) {
3739: PetscDualSpace dsp;
3741: PetscFEGetDualSpace((PetscFE)disc,&dsp);
3742: DMLabelGetNumValues(label,&depth);
3743: DMLabelGetValue(label,point,&h);
3744: h = depth - 1 - h;
3745: if (h) {
3746: PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3747: } else {
3748: *dspace = dsp;
3749: }
3750: }
3751: }
3752: return(0);
3753: }
3756: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3757: {
3758: PetscScalar *array, *vArray;
3759: const PetscInt *cone, *coneO;
3760: PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0;
3761: PetscErrorCode ierr;
3764: PetscSectionGetChart(section, &pStart, &pEnd);
3765: DMPlexGetConeSize(dm, point, &numPoints);
3766: DMPlexGetCone(dm, point, &cone);
3767: DMPlexGetConeOrientation(dm, point, &coneO);
3768: if (!values || !*values) {
3769: if ((point >= pStart) && (point < pEnd)) {
3770: PetscInt dof;
3772: PetscSectionGetDof(section, point, &dof);
3773: size += dof;
3774: }
3775: for (p = 0; p < numPoints; ++p) {
3776: const PetscInt cp = cone[p];
3777: PetscInt dof;
3779: if ((cp < pStart) || (cp >= pEnd)) continue;
3780: PetscSectionGetDof(section, cp, &dof);
3781: size += dof;
3782: }
3783: if (!values) {
3784: if (csize) *csize = size;
3785: return(0);
3786: }
3787: DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
3788: } else {
3789: array = *values;
3790: }
3791: size = 0;
3792: VecGetArray(v, &vArray);
3793: if ((point >= pStart) && (point < pEnd)) {
3794: PetscInt dof, off, d;
3795: PetscScalar *varr;
3797: PetscSectionGetDof(section, point, &dof);
3798: PetscSectionGetOffset(section, point, &off);
3799: varr = &vArray[off];
3800: for (d = 0; d < dof; ++d, ++offset) {
3801: array[offset] = varr[d];
3802: }
3803: size += dof;
3804: }
3805: for (p = 0; p < numPoints; ++p) {
3806: const PetscInt cp = cone[p];
3807: PetscInt o = coneO[p];
3808: PetscInt dof, off, d;
3809: PetscScalar *varr;
3811: if ((cp < pStart) || (cp >= pEnd)) continue;
3812: PetscSectionGetDof(section, cp, &dof);
3813: PetscSectionGetOffset(section, cp, &off);
3814: varr = &vArray[off];
3815: if (o >= 0) {
3816: for (d = 0; d < dof; ++d, ++offset) {
3817: array[offset] = varr[d];
3818: }
3819: } else {
3820: for (d = dof-1; d >= 0; --d, ++offset) {
3821: array[offset] = varr[d];
3822: }
3823: }
3824: size += dof;
3825: }
3826: VecRestoreArray(v, &vArray);
3827: if (!*values) {
3828: if (csize) *csize = size;
3829: *values = array;
3830: } else {
3831: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3832: *csize = size;
3833: }
3834: return(0);
3835: }
3837: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3838: {
3839: const PetscInt *cla;
3840: PetscInt np, *pts = NULL;
3844: PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3845: if (!*clPoints) {
3846: PetscInt pStart, pEnd, p, q;
3848: PetscSectionGetChart(section, &pStart, &pEnd);
3849: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3850: /* Compress out points not in the section */
3851: for (p = 0, q = 0; p < np; p++) {
3852: PetscInt r = pts[2*p];
3853: if ((r >= pStart) && (r < pEnd)) {
3854: pts[q*2] = r;
3855: pts[q*2+1] = pts[2*p+1];
3856: ++q;
3857: }
3858: }
3859: np = q;
3860: cla = NULL;
3861: } else {
3862: PetscInt dof, off;
3864: PetscSectionGetDof(*clSec, point, &dof);
3865: PetscSectionGetOffset(*clSec, point, &off);
3866: ISGetIndices(*clPoints, &cla);
3867: np = dof/2;
3868: pts = (PetscInt *) &cla[off];
3869: }
3870: *numPoints = np;
3871: *points = pts;
3872: *clp = cla;
3874: return(0);
3875: }
3877: static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3878: {
3882: if (!*clPoints) {
3883: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3884: } else {
3885: ISRestoreIndices(*clPoints, clp);
3886: }
3887: *numPoints = 0;
3888: *points = NULL;
3889: *clSec = NULL;
3890: *clPoints = NULL;
3891: *clp = NULL;
3892: return(0);
3893: }
3895: 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[])
3896: {
3897: PetscInt offset = 0, p;
3898: const PetscInt **perms = NULL;
3899: const PetscScalar **flips = NULL;
3900: PetscErrorCode ierr;
3903: *size = 0;
3904: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3905: for (p = 0; p < numPoints; p++) {
3906: const PetscInt point = points[2*p];
3907: const PetscInt *perm = perms ? perms[p] : NULL;
3908: const PetscScalar *flip = flips ? flips[p] : NULL;
3909: PetscInt dof, off, d;
3910: const PetscScalar *varr;
3912: PetscSectionGetDof(section, point, &dof);
3913: PetscSectionGetOffset(section, point, &off);
3914: varr = &vArray[off];
3915: if (clperm) {
3916: if (perm) {
3917: for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
3918: } else {
3919: for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d];
3920: }
3921: if (flip) {
3922: for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d];
3923: }
3924: } else {
3925: if (perm) {
3926: for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
3927: } else {
3928: for (d = 0; d < dof; d++) array[offset + d ] = varr[d];
3929: }
3930: if (flip) {
3931: for (d = 0; d < dof; d++) array[offset + d ] *= flip[d];
3932: }
3933: }
3934: offset += dof;
3935: }
3936: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3937: *size = offset;
3938: return(0);
3939: }
3941: 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[])
3942: {
3943: PetscInt offset = 0, f;
3944: PetscErrorCode ierr;
3947: *size = 0;
3948: for (f = 0; f < numFields; ++f) {
3949: PetscInt p;
3950: const PetscInt **perms = NULL;
3951: const PetscScalar **flips = NULL;
3953: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3954: for (p = 0; p < numPoints; p++) {
3955: const PetscInt point = points[2*p];
3956: PetscInt fdof, foff, b;
3957: const PetscScalar *varr;
3958: const PetscInt *perm = perms ? perms[p] : NULL;
3959: const PetscScalar *flip = flips ? flips[p] : NULL;
3961: PetscSectionGetFieldDof(section, point, f, &fdof);
3962: PetscSectionGetFieldOffset(section, point, f, &foff);
3963: varr = &vArray[foff];
3964: if (clperm) {
3965: if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}}
3966: else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}}
3967: if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}}
3968: } else {
3969: if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}}
3970: else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}}
3971: if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}}
3972: }
3973: offset += fdof;
3974: }
3975: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3976: }
3977: *size = offset;
3978: return(0);
3979: }
3981: /*@C
3982: DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
3984: Not collective
3986: Input Parameters:
3987: + dm - The DM
3988: . section - The section describing the layout in v, or NULL to use the default section
3989: . v - The local vector
3990: - point - The sieve point in the DM
3992: Output Parameters:
3993: + csize - The number of values in the closure, or NULL
3994: - values - The array of values, which is a borrowed array and should not be freed
3996: Fortran Notes:
3997: Since it returns an array, this routine is only available in Fortran 90, and you must
3998: include petsc.h90 in your code.
4000: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4002: Level: intermediate
4004: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4005: @*/
4006: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4007: {
4008: PetscSection clSection;
4009: IS clPoints;
4010: PetscScalar *array;
4011: const PetscScalar *vArray;
4012: PetscInt *points = NULL;
4013: const PetscInt *clp, *perm;
4014: PetscInt depth, numFields, numPoints, size;
4015: PetscErrorCode ierr;
4019: if (!section) {DMGetDefaultSection(dm, §ion);}
4022: DMPlexGetDepth(dm, &depth);
4023: PetscSectionGetNumFields(section, &numFields);
4024: if (depth == 1 && numFields < 2) {
4025: DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4026: return(0);
4027: }
4028: /* Get points */
4029: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4030: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4031: /* Get array */
4032: if (!values || !*values) {
4033: PetscInt asize = 0, dof, p;
4035: for (p = 0; p < numPoints*2; p += 2) {
4036: PetscSectionGetDof(section, points[p], &dof);
4037: asize += dof;
4038: }
4039: if (!values) {
4040: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4041: if (csize) *csize = asize;
4042: return(0);
4043: }
4044: DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
4045: } else {
4046: array = *values;
4047: }
4048: VecGetArrayRead(v, &vArray);
4049: /* Get values */
4050: if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4051: else {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4052: /* Cleanup points */
4053: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4054: /* Cleanup array */
4055: VecRestoreArrayRead(v, &vArray);
4056: if (!*values) {
4057: if (csize) *csize = size;
4058: *values = array;
4059: } else {
4060: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4061: *csize = size;
4062: }
4063: return(0);
4064: }
4066: /*@C
4067: DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4069: Not collective
4071: Input Parameters:
4072: + dm - The DM
4073: . section - The section describing the layout in v, or NULL to use the default section
4074: . v - The local vector
4075: . point - The sieve point in the DM
4076: . csize - The number of values in the closure, or NULL
4077: - values - The array of values, which is a borrowed array and should not be freed
4079: Fortran Notes:
4080: Since it returns an array, this routine is only available in Fortran 90, and you must
4081: include petsc.h90 in your code.
4083: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4085: Level: intermediate
4087: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4088: @*/
4089: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4090: {
4091: PetscInt size = 0;
4095: /* Should work without recalculating size */
4096: DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
4097: return(0);
4098: }
4100: PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;}
4101: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;}
4103: 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[])
4104: {
4105: PetscInt cdof; /* The number of constraints on this point */
4106: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4107: PetscScalar *a;
4108: PetscInt off, cind = 0, k;
4109: PetscErrorCode ierr;
4112: PetscSectionGetConstraintDof(section, point, &cdof);
4113: PetscSectionGetOffset(section, point, &off);
4114: a = &array[off];
4115: if (!cdof || setBC) {
4116: if (clperm) {
4117: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4118: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}}
4119: } else {
4120: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4121: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}}
4122: }
4123: } else {
4124: PetscSectionGetConstraintIndices(section, point, &cdofs);
4125: if (clperm) {
4126: if (perm) {for (k = 0; k < dof; ++k) {
4127: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4128: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4129: }
4130: } else {
4131: for (k = 0; k < dof; ++k) {
4132: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4133: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4134: }
4135: }
4136: } else {
4137: if (perm) {
4138: for (k = 0; k < dof; ++k) {
4139: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4140: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4141: }
4142: } else {
4143: for (k = 0; k < dof; ++k) {
4144: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4145: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4146: }
4147: }
4148: }
4149: }
4150: return(0);
4151: }
4153: 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[])
4154: {
4155: PetscInt cdof; /* The number of constraints on this point */
4156: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4157: PetscScalar *a;
4158: PetscInt off, cind = 0, k;
4159: PetscErrorCode ierr;
4162: PetscSectionGetConstraintDof(section, point, &cdof);
4163: PetscSectionGetOffset(section, point, &off);
4164: a = &array[off];
4165: if (cdof) {
4166: PetscSectionGetConstraintIndices(section, point, &cdofs);
4167: if (clperm) {
4168: if (perm) {
4169: for (k = 0; k < dof; ++k) {
4170: if ((cind < cdof) && (k == cdofs[cind])) {
4171: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4172: cind++;
4173: }
4174: }
4175: } else {
4176: for (k = 0; k < dof; ++k) {
4177: if ((cind < cdof) && (k == cdofs[cind])) {
4178: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4179: cind++;
4180: }
4181: }
4182: }
4183: } else {
4184: if (perm) {
4185: for (k = 0; k < dof; ++k) {
4186: if ((cind < cdof) && (k == cdofs[cind])) {
4187: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4188: cind++;
4189: }
4190: }
4191: } else {
4192: for (k = 0; k < dof; ++k) {
4193: if ((cind < cdof) && (k == cdofs[cind])) {
4194: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4195: cind++;
4196: }
4197: }
4198: }
4199: }
4200: }
4201: return(0);
4202: }
4204: 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[])
4205: {
4206: PetscScalar *a;
4207: PetscInt fdof, foff, fcdof, foffset = *offset;
4208: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4209: PetscInt cind = 0, b;
4210: PetscErrorCode ierr;
4213: PetscSectionGetFieldDof(section, point, f, &fdof);
4214: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4215: PetscSectionGetFieldOffset(section, point, f, &foff);
4216: a = &array[foff];
4217: if (!fcdof || setBC) {
4218: if (clperm) {
4219: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4220: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}}
4221: } else {
4222: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4223: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}}
4224: }
4225: } else {
4226: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4227: if (clperm) {
4228: if (perm) {
4229: for (b = 0; b < fdof; b++) {
4230: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4231: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4232: }
4233: } else {
4234: for (b = 0; b < fdof; b++) {
4235: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4236: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4237: }
4238: }
4239: } else {
4240: if (perm) {
4241: for (b = 0; b < fdof; b++) {
4242: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4243: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4244: }
4245: } else {
4246: for (b = 0; b < fdof; b++) {
4247: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4248: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4249: }
4250: }
4251: }
4252: }
4253: *offset += fdof;
4254: return(0);
4255: }
4257: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4258: {
4259: PetscScalar *a;
4260: PetscInt fdof, foff, fcdof, foffset = *offset;
4261: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4262: PetscInt cind = 0, b;
4263: PetscErrorCode ierr;
4266: PetscSectionGetFieldDof(section, point, f, &fdof);
4267: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4268: PetscSectionGetFieldOffset(section, point, f, &foff);
4269: a = &array[foff];
4270: if (fcdof) {
4271: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4272: if (clperm) {
4273: if (perm) {
4274: for (b = 0; b < fdof; b++) {
4275: if ((cind < fcdof) && (b == fcdofs[cind])) {
4276: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4277: ++cind;
4278: }
4279: }
4280: } else {
4281: for (b = 0; b < fdof; b++) {
4282: if ((cind < fcdof) && (b == fcdofs[cind])) {
4283: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4284: ++cind;
4285: }
4286: }
4287: }
4288: } else {
4289: if (perm) {
4290: for (b = 0; b < fdof; b++) {
4291: if ((cind < fcdof) && (b == fcdofs[cind])) {
4292: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4293: ++cind;
4294: }
4295: }
4296: } else {
4297: for (b = 0; b < fdof; b++) {
4298: if ((cind < fcdof) && (b == fcdofs[cind])) {
4299: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4300: ++cind;
4301: }
4302: }
4303: }
4304: }
4305: }
4306: *offset += fdof;
4307: return(0);
4308: }
4310: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4311: {
4312: PetscScalar *array;
4313: const PetscInt *cone, *coneO;
4314: PetscInt pStart, pEnd, p, numPoints, off, dof;
4315: PetscErrorCode ierr;
4318: PetscSectionGetChart(section, &pStart, &pEnd);
4319: DMPlexGetConeSize(dm, point, &numPoints);
4320: DMPlexGetCone(dm, point, &cone);
4321: DMPlexGetConeOrientation(dm, point, &coneO);
4322: VecGetArray(v, &array);
4323: for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4324: const PetscInt cp = !p ? point : cone[p-1];
4325: const PetscInt o = !p ? 0 : coneO[p-1];
4327: if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4328: PetscSectionGetDof(section, cp, &dof);
4329: /* ADD_VALUES */
4330: {
4331: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4332: PetscScalar *a;
4333: PetscInt cdof, coff, cind = 0, k;
4335: PetscSectionGetConstraintDof(section, cp, &cdof);
4336: PetscSectionGetOffset(section, cp, &coff);
4337: a = &array[coff];
4338: if (!cdof) {
4339: if (o >= 0) {
4340: for (k = 0; k < dof; ++k) {
4341: a[k] += values[off+k];
4342: }
4343: } else {
4344: for (k = 0; k < dof; ++k) {
4345: a[k] += values[off+dof-k-1];
4346: }
4347: }
4348: } else {
4349: PetscSectionGetConstraintIndices(section, cp, &cdofs);
4350: if (o >= 0) {
4351: for (k = 0; k < dof; ++k) {
4352: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4353: a[k] += values[off+k];
4354: }
4355: } else {
4356: for (k = 0; k < dof; ++k) {
4357: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4358: a[k] += values[off+dof-k-1];
4359: }
4360: }
4361: }
4362: }
4363: }
4364: VecRestoreArray(v, &array);
4365: return(0);
4366: }
4368: /*@C
4369: DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4371: Not collective
4373: Input Parameters:
4374: + dm - The DM
4375: . section - The section describing the layout in v, or NULL to use the default section
4376: . v - The local vector
4377: . point - The sieve point in the DM
4378: . values - The array of values
4379: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
4381: Fortran Notes:
4382: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4384: Level: intermediate
4386: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4387: @*/
4388: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4389: {
4390: PetscSection clSection;
4391: IS clPoints;
4392: PetscScalar *array;
4393: PetscInt *points = NULL;
4394: const PetscInt *clp, *clperm;
4395: PetscInt depth, numFields, numPoints, p;
4396: PetscErrorCode ierr;
4400: if (!section) {DMGetDefaultSection(dm, §ion);}
4403: DMPlexGetDepth(dm, &depth);
4404: PetscSectionGetNumFields(section, &numFields);
4405: if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4406: DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4407: return(0);
4408: }
4409: /* Get points */
4410: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4411: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4412: /* Get array */
4413: VecGetArray(v, &array);
4414: /* Get values */
4415: if (numFields > 0) {
4416: PetscInt offset = 0, f;
4417: for (f = 0; f < numFields; ++f) {
4418: const PetscInt **perms = NULL;
4419: const PetscScalar **flips = NULL;
4421: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4422: switch (mode) {
4423: case INSERT_VALUES:
4424: for (p = 0; p < numPoints; p++) {
4425: const PetscInt point = points[2*p];
4426: const PetscInt *perm = perms ? perms[p] : NULL;
4427: const PetscScalar *flip = flips ? flips[p] : NULL;
4428: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4429: } break;
4430: case INSERT_ALL_VALUES:
4431: for (p = 0; p < numPoints; p++) {
4432: const PetscInt point = points[2*p];
4433: const PetscInt *perm = perms ? perms[p] : NULL;
4434: const PetscScalar *flip = flips ? flips[p] : NULL;
4435: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4436: } break;
4437: case INSERT_BC_VALUES:
4438: for (p = 0; p < numPoints; p++) {
4439: const PetscInt point = points[2*p];
4440: const PetscInt *perm = perms ? perms[p] : NULL;
4441: const PetscScalar *flip = flips ? flips[p] : NULL;
4442: updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4443: } break;
4444: case ADD_VALUES:
4445: for (p = 0; p < numPoints; p++) {
4446: const PetscInt point = points[2*p];
4447: const PetscInt *perm = perms ? perms[p] : NULL;
4448: const PetscScalar *flip = flips ? flips[p] : NULL;
4449: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4450: } break;
4451: case ADD_ALL_VALUES:
4452: for (p = 0; p < numPoints; p++) {
4453: const PetscInt point = points[2*p];
4454: const PetscInt *perm = perms ? perms[p] : NULL;
4455: const PetscScalar *flip = flips ? flips[p] : NULL;
4456: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4457: } break;
4458: case ADD_BC_VALUES:
4459: for (p = 0; p < numPoints; p++) {
4460: const PetscInt point = points[2*p];
4461: const PetscInt *perm = perms ? perms[p] : NULL;
4462: const PetscScalar *flip = flips ? flips[p] : NULL;
4463: updatePointFieldsBC_private(section, point, perm, flip, f, add, clperm, values, &offset, array);
4464: } break;
4465: default:
4466: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4467: }
4468: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4469: }
4470: } else {
4471: PetscInt dof, off;
4472: const PetscInt **perms = NULL;
4473: const PetscScalar **flips = NULL;
4475: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4476: switch (mode) {
4477: case INSERT_VALUES:
4478: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4479: const PetscInt point = points[2*p];
4480: const PetscInt *perm = perms ? perms[p] : NULL;
4481: const PetscScalar *flip = flips ? flips[p] : NULL;
4482: PetscSectionGetDof(section, point, &dof);
4483: updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4484: } break;
4485: case INSERT_ALL_VALUES:
4486: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4487: const PetscInt point = points[2*p];
4488: const PetscInt *perm = perms ? perms[p] : NULL;
4489: const PetscScalar *flip = flips ? flips[p] : NULL;
4490: PetscSectionGetDof(section, point, &dof);
4491: updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array);
4492: } break;
4493: case INSERT_BC_VALUES:
4494: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4495: const PetscInt point = points[2*p];
4496: const PetscInt *perm = perms ? perms[p] : NULL;
4497: const PetscScalar *flip = flips ? flips[p] : NULL;
4498: PetscSectionGetDof(section, point, &dof);
4499: updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array);
4500: } break;
4501: case ADD_VALUES:
4502: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4503: const PetscInt point = points[2*p];
4504: const PetscInt *perm = perms ? perms[p] : NULL;
4505: const PetscScalar *flip = flips ? flips[p] : NULL;
4506: PetscSectionGetDof(section, point, &dof);
4507: updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array);
4508: } break;
4509: case ADD_ALL_VALUES:
4510: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4511: const PetscInt point = points[2*p];
4512: const PetscInt *perm = perms ? perms[p] : NULL;
4513: const PetscScalar *flip = flips ? flips[p] : NULL;
4514: PetscSectionGetDof(section, point, &dof);
4515: updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array);
4516: } break;
4517: case ADD_BC_VALUES:
4518: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4519: const PetscInt point = points[2*p];
4520: const PetscInt *perm = perms ? perms[p] : NULL;
4521: const PetscScalar *flip = flips ? flips[p] : NULL;
4522: PetscSectionGetDof(section, point, &dof);
4523: updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array);
4524: } break;
4525: default:
4526: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4527: }
4528: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4529: }
4530: /* Cleanup points */
4531: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4532: /* Cleanup array */
4533: VecRestoreArray(v, &array);
4534: return(0);
4535: }
4537: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4538: {
4539: PetscSection clSection;
4540: IS clPoints;
4541: PetscScalar *array;
4542: PetscInt *points = NULL;
4543: const PetscInt *clp, *clperm;
4544: PetscInt numFields, numPoints, p;
4545: PetscInt offset = 0, f;
4546: PetscErrorCode ierr;
4550: if (!section) {DMGetDefaultSection(dm, §ion);}
4553: PetscSectionGetNumFields(section, &numFields);
4554: /* Get points */
4555: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4556: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4557: /* Get array */
4558: VecGetArray(v, &array);
4559: /* Get values */
4560: for (f = 0; f < numFields; ++f) {
4561: const PetscInt **perms = NULL;
4562: const PetscScalar **flips = NULL;
4564: if (!fieldActive[f]) {
4565: for (p = 0; p < numPoints*2; p += 2) {
4566: PetscInt fdof;
4567: PetscSectionGetFieldDof(section, points[p], f, &fdof);
4568: offset += fdof;
4569: }
4570: continue;
4571: }
4572: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4573: switch (mode) {
4574: case INSERT_VALUES:
4575: for (p = 0; p < numPoints; p++) {
4576: const PetscInt point = points[2*p];
4577: const PetscInt *perm = perms ? perms[p] : NULL;
4578: const PetscScalar *flip = flips ? flips[p] : NULL;
4579: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4580: } break;
4581: case INSERT_ALL_VALUES:
4582: for (p = 0; p < numPoints; p++) {
4583: const PetscInt point = points[2*p];
4584: const PetscInt *perm = perms ? perms[p] : NULL;
4585: const PetscScalar *flip = flips ? flips[p] : NULL;
4586: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4587: } break;
4588: case INSERT_BC_VALUES:
4589: for (p = 0; p < numPoints; p++) {
4590: const PetscInt point = points[2*p];
4591: const PetscInt *perm = perms ? perms[p] : NULL;
4592: const PetscScalar *flip = flips ? flips[p] : NULL;
4593: updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4594: } break;
4595: case ADD_VALUES:
4596: for (p = 0; p < numPoints; p++) {
4597: const PetscInt point = points[2*p];
4598: const PetscInt *perm = perms ? perms[p] : NULL;
4599: const PetscScalar *flip = flips ? flips[p] : NULL;
4600: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4601: } break;
4602: case ADD_ALL_VALUES:
4603: for (p = 0; p < numPoints; p++) {
4604: const PetscInt point = points[2*p];
4605: const PetscInt *perm = perms ? perms[p] : NULL;
4606: const PetscScalar *flip = flips ? flips[p] : NULL;
4607: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4608: } break;
4609: default:
4610: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4611: }
4612: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4613: }
4614: /* Cleanup points */
4615: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4616: /* Cleanup array */
4617: VecRestoreArray(v, &array);
4618: return(0);
4619: }
4621: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4622: {
4623: PetscMPIInt rank;
4624: PetscInt i, j;
4628: MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4629: PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);
4630: for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4631: for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4632: numCIndices = numCIndices ? numCIndices : numRIndices;
4633: for (i = 0; i < numRIndices; i++) {
4634: PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4635: for (j = 0; j < numCIndices; j++) {
4636: #if defined(PETSC_USE_COMPLEX)
4637: PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4638: #else
4639: PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4640: #endif
4641: }
4642: PetscViewerASCIIPrintf(viewer, "\n");
4643: }
4644: return(0);
4645: }
4647: /* . off - The global offset of this point */
4648: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4649: {
4650: PetscInt dof; /* The number of unknowns on this point */
4651: PetscInt cdof; /* The number of constraints on this point */
4652: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4653: PetscInt cind = 0, k;
4654: PetscErrorCode ierr;
4657: PetscSectionGetDof(section, point, &dof);
4658: PetscSectionGetConstraintDof(section, point, &cdof);
4659: if (!cdof || setBC) {
4660: if (perm) {
4661: for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4662: } else {
4663: for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4664: }
4665: } else {
4666: PetscSectionGetConstraintIndices(section, point, &cdofs);
4667: if (perm) {
4668: for (k = 0; k < dof; ++k) {
4669: if ((cind < cdof) && (k == cdofs[cind])) {
4670: /* Insert check for returning constrained indices */
4671: indices[*loff+perm[k]] = -(off+k+1);
4672: ++cind;
4673: } else {
4674: indices[*loff+perm[k]] = off+k-cind;
4675: }
4676: }
4677: } else {
4678: for (k = 0; k < dof; ++k) {
4679: if ((cind < cdof) && (k == cdofs[cind])) {
4680: /* Insert check for returning constrained indices */
4681: indices[*loff+k] = -(off+k+1);
4682: ++cind;
4683: } else {
4684: indices[*loff+k] = off+k-cind;
4685: }
4686: }
4687: }
4688: }
4689: *loff += dof;
4690: return(0);
4691: }
4693: /* . off - The global offset of this point */
4694: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4695: {
4696: PetscInt numFields, foff, f;
4700: PetscSectionGetNumFields(section, &numFields);
4701: for (f = 0, foff = 0; f < numFields; ++f) {
4702: PetscInt fdof, cfdof;
4703: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4704: PetscInt cind = 0, b;
4705: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4707: PetscSectionGetFieldDof(section, point, f, &fdof);
4708: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4709: if (!cfdof || setBC) {
4710: if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4711: else {for (b = 0; b < fdof; b++) {indices[foffs[f]+ b ] = off+foff+b;}}
4712: } else {
4713: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4714: if (perm) {
4715: for (b = 0; b < fdof; b++) {
4716: if ((cind < cfdof) && (b == fcdofs[cind])) {
4717: indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4718: ++cind;
4719: } else {
4720: indices[foffs[f]+perm[b]] = off+foff+b-cind;
4721: }
4722: }
4723: } else {
4724: for (b = 0; b < fdof; b++) {
4725: if ((cind < cfdof) && (b == fcdofs[cind])) {
4726: indices[foffs[f]+b] = -(off+foff+b+1);
4727: ++cind;
4728: } else {
4729: indices[foffs[f]+b] = off+foff+b-cind;
4730: }
4731: }
4732: }
4733: }
4734: foff += (setBC ? fdof : (fdof - cfdof));
4735: foffs[f] += fdof;
4736: }
4737: return(0);
4738: }
4740: 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)
4741: {
4742: Mat cMat;
4743: PetscSection aSec, cSec;
4744: IS aIS;
4745: PetscInt aStart = -1, aEnd = -1;
4746: const PetscInt *anchors;
4747: PetscInt numFields, f, p, q, newP = 0;
4748: PetscInt newNumPoints = 0, newNumIndices = 0;
4749: PetscInt *newPoints, *indices, *newIndices;
4750: PetscInt maxAnchor, maxDof;
4751: PetscInt newOffsets[32];
4752: PetscInt *pointMatOffsets[32];
4753: PetscInt *newPointOffsets[32];
4754: PetscScalar *pointMat[32];
4755: PetscScalar *newValues=NULL,*tmpValues;
4756: PetscBool anyConstrained = PETSC_FALSE;
4757: PetscErrorCode ierr;
4762: PetscSectionGetNumFields(section, &numFields);
4764: DMPlexGetAnchors(dm,&aSec,&aIS);
4765: /* if there are point-to-point constraints */
4766: if (aSec) {
4767: PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4768: ISGetIndices(aIS,&anchors);
4769: PetscSectionGetChart(aSec,&aStart,&aEnd);
4770: /* figure out how many points are going to be in the new element matrix
4771: * (we allow double counting, because it's all just going to be summed
4772: * into the global matrix anyway) */
4773: for (p = 0; p < 2*numPoints; p+=2) {
4774: PetscInt b = points[p];
4775: PetscInt bDof = 0, bSecDof;
4777: PetscSectionGetDof(section,b,&bSecDof);
4778: if (!bSecDof) {
4779: continue;
4780: }
4781: if (b >= aStart && b < aEnd) {
4782: PetscSectionGetDof(aSec,b,&bDof);
4783: }
4784: if (bDof) {
4785: /* this point is constrained */
4786: /* it is going to be replaced by its anchors */
4787: PetscInt bOff, q;
4789: anyConstrained = PETSC_TRUE;
4790: newNumPoints += bDof;
4791: PetscSectionGetOffset(aSec,b,&bOff);
4792: for (q = 0; q < bDof; q++) {
4793: PetscInt a = anchors[bOff + q];
4794: PetscInt aDof;
4796: PetscSectionGetDof(section,a,&aDof);
4797: newNumIndices += aDof;
4798: for (f = 0; f < numFields; ++f) {
4799: PetscInt fDof;
4801: PetscSectionGetFieldDof(section, a, f, &fDof);
4802: newOffsets[f+1] += fDof;
4803: }
4804: }
4805: }
4806: else {
4807: /* this point is not constrained */
4808: newNumPoints++;
4809: newNumIndices += bSecDof;
4810: for (f = 0; f < numFields; ++f) {
4811: PetscInt fDof;
4813: PetscSectionGetFieldDof(section, b, f, &fDof);
4814: newOffsets[f+1] += fDof;
4815: }
4816: }
4817: }
4818: }
4819: if (!anyConstrained) {
4820: if (outNumPoints) *outNumPoints = 0;
4821: if (outNumIndices) *outNumIndices = 0;
4822: if (outPoints) *outPoints = NULL;
4823: if (outValues) *outValues = NULL;
4824: if (aSec) {ISRestoreIndices(aIS,&anchors);}
4825: return(0);
4826: }
4828: if (outNumPoints) *outNumPoints = newNumPoints;
4829: if (outNumIndices) *outNumIndices = newNumIndices;
4831: for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
4833: if (!outPoints && !outValues) {
4834: if (offsets) {
4835: for (f = 0; f <= numFields; f++) {
4836: offsets[f] = newOffsets[f];
4837: }
4838: }
4839: if (aSec) {ISRestoreIndices(aIS,&anchors);}
4840: return(0);
4841: }
4843: if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
4845: DMGetDefaultConstraints(dm, &cSec, &cMat);
4847: /* workspaces */
4848: if (numFields) {
4849: for (f = 0; f < numFields; f++) {
4850: DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4851: DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4852: }
4853: }
4854: else {
4855: DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4856: DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
4857: }
4859: /* get workspaces for the point-to-point matrices */
4860: if (numFields) {
4861: PetscInt totalOffset, totalMatOffset;
4863: for (p = 0; p < numPoints; p++) {
4864: PetscInt b = points[2*p];
4865: PetscInt bDof = 0, bSecDof;
4867: PetscSectionGetDof(section,b,&bSecDof);
4868: if (!bSecDof) {
4869: for (f = 0; f < numFields; f++) {
4870: newPointOffsets[f][p + 1] = 0;
4871: pointMatOffsets[f][p + 1] = 0;
4872: }
4873: continue;
4874: }
4875: if (b >= aStart && b < aEnd) {
4876: PetscSectionGetDof(aSec, b, &bDof);
4877: }
4878: if (bDof) {
4879: for (f = 0; f < numFields; f++) {
4880: PetscInt fDof, q, bOff, allFDof = 0;
4882: PetscSectionGetFieldDof(section, b, f, &fDof);
4883: PetscSectionGetOffset(aSec, b, &bOff);
4884: for (q = 0; q < bDof; q++) {
4885: PetscInt a = anchors[bOff + q];
4886: PetscInt aFDof;
4888: PetscSectionGetFieldDof(section, a, f, &aFDof);
4889: allFDof += aFDof;
4890: }
4891: newPointOffsets[f][p+1] = allFDof;
4892: pointMatOffsets[f][p+1] = fDof * allFDof;
4893: }
4894: }
4895: else {
4896: for (f = 0; f < numFields; f++) {
4897: PetscInt fDof;
4899: PetscSectionGetFieldDof(section, b, f, &fDof);
4900: newPointOffsets[f][p+1] = fDof;
4901: pointMatOffsets[f][p+1] = 0;
4902: }
4903: }
4904: }
4905: for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4906: newPointOffsets[f][0] = totalOffset;
4907: pointMatOffsets[f][0] = totalMatOffset;
4908: for (p = 0; p < numPoints; p++) {
4909: newPointOffsets[f][p+1] += newPointOffsets[f][p];
4910: pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4911: }
4912: totalOffset = newPointOffsets[f][numPoints];
4913: totalMatOffset = pointMatOffsets[f][numPoints];
4914: DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4915: }
4916: }
4917: else {
4918: for (p = 0; p < numPoints; p++) {
4919: PetscInt b = points[2*p];
4920: PetscInt bDof = 0, bSecDof;
4922: PetscSectionGetDof(section,b,&bSecDof);
4923: if (!bSecDof) {
4924: newPointOffsets[0][p + 1] = 0;
4925: pointMatOffsets[0][p + 1] = 0;
4926: continue;
4927: }
4928: if (b >= aStart && b < aEnd) {
4929: PetscSectionGetDof(aSec, b, &bDof);
4930: }
4931: if (bDof) {
4932: PetscInt bOff, q, allDof = 0;
4934: PetscSectionGetOffset(aSec, b, &bOff);
4935: for (q = 0; q < bDof; q++) {
4936: PetscInt a = anchors[bOff + q], aDof;
4938: PetscSectionGetDof(section, a, &aDof);
4939: allDof += aDof;
4940: }
4941: newPointOffsets[0][p+1] = allDof;
4942: pointMatOffsets[0][p+1] = bSecDof * allDof;
4943: }
4944: else {
4945: newPointOffsets[0][p+1] = bSecDof;
4946: pointMatOffsets[0][p+1] = 0;
4947: }
4948: }
4949: newPointOffsets[0][0] = 0;
4950: pointMatOffsets[0][0] = 0;
4951: for (p = 0; p < numPoints; p++) {
4952: newPointOffsets[0][p+1] += newPointOffsets[0][p];
4953: pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4954: }
4955: DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4956: }
4958: /* output arrays */
4959: DMGetWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
4961: /* get the point-to-point matrices; construct newPoints */
4962: PetscSectionGetMaxDof(aSec, &maxAnchor);
4963: PetscSectionGetMaxDof(section, &maxDof);
4964: DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
4965: DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
4966: if (numFields) {
4967: for (p = 0, newP = 0; p < numPoints; p++) {
4968: PetscInt b = points[2*p];
4969: PetscInt o = points[2*p+1];
4970: PetscInt bDof = 0, bSecDof;
4972: PetscSectionGetDof(section, b, &bSecDof);
4973: if (!bSecDof) {
4974: continue;
4975: }
4976: if (b >= aStart && b < aEnd) {
4977: PetscSectionGetDof(aSec, b, &bDof);
4978: }
4979: if (bDof) {
4980: PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
4982: fStart[0] = 0;
4983: fEnd[0] = 0;
4984: for (f = 0; f < numFields; f++) {
4985: PetscInt fDof;
4987: PetscSectionGetFieldDof(cSec, b, f, &fDof);
4988: fStart[f+1] = fStart[f] + fDof;
4989: fEnd[f+1] = fStart[f+1];
4990: }
4991: PetscSectionGetOffset(cSec, b, &bOff);
4992: DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);
4994: fAnchorStart[0] = 0;
4995: fAnchorEnd[0] = 0;
4996: for (f = 0; f < numFields; f++) {
4997: PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
4999: fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5000: fAnchorEnd[f+1] = fAnchorStart[f + 1];
5001: }
5002: PetscSectionGetOffset(aSec, b, &bOff);
5003: for (q = 0; q < bDof; q++) {
5004: PetscInt a = anchors[bOff + q], aOff;
5006: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5007: newPoints[2*(newP + q)] = a;
5008: newPoints[2*(newP + q) + 1] = 0;
5009: PetscSectionGetOffset(section, a, &aOff);
5010: DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5011: }
5012: newP += bDof;
5014: if (outValues) {
5015: /* get the point-to-point submatrix */
5016: for (f = 0; f < numFields; f++) {
5017: MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5018: }
5019: }
5020: }
5021: else {
5022: newPoints[2 * newP] = b;
5023: newPoints[2 * newP + 1] = o;
5024: newP++;
5025: }
5026: }
5027: } else {
5028: for (p = 0; p < numPoints; p++) {
5029: PetscInt b = points[2*p];
5030: PetscInt o = points[2*p+1];
5031: PetscInt bDof = 0, bSecDof;
5033: PetscSectionGetDof(section, b, &bSecDof);
5034: if (!bSecDof) {
5035: continue;
5036: }
5037: if (b >= aStart && b < aEnd) {
5038: PetscSectionGetDof(aSec, b, &bDof);
5039: }
5040: if (bDof) {
5041: PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5043: PetscSectionGetOffset(cSec, b, &bOff);
5044: DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);
5046: PetscSectionGetOffset (aSec, b, &bOff);
5047: for (q = 0; q < bDof; q++) {
5048: PetscInt a = anchors[bOff + q], aOff;
5050: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5052: newPoints[2*(newP + q)] = a;
5053: newPoints[2*(newP + q) + 1] = 0;
5054: PetscSectionGetOffset(section, a, &aOff);
5055: DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5056: }
5057: newP += bDof;
5059: /* get the point-to-point submatrix */
5060: if (outValues) {
5061: MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5062: }
5063: }
5064: else {
5065: newPoints[2 * newP] = b;
5066: newPoints[2 * newP + 1] = o;
5067: newP++;
5068: }
5069: }
5070: }
5072: if (outValues) {
5073: DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5074: PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5075: /* multiply constraints on the right */
5076: if (numFields) {
5077: for (f = 0; f < numFields; f++) {
5078: PetscInt oldOff = offsets[f];
5080: for (p = 0; p < numPoints; p++) {
5081: PetscInt cStart = newPointOffsets[f][p];
5082: PetscInt b = points[2 * p];
5083: PetscInt c, r, k;
5084: PetscInt dof;
5086: PetscSectionGetFieldDof(section,b,f,&dof);
5087: if (!dof) {
5088: continue;
5089: }
5090: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5091: PetscInt nCols = newPointOffsets[f][p+1]-cStart;
5092: const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5094: for (r = 0; r < numIndices; r++) {
5095: for (c = 0; c < nCols; c++) {
5096: for (k = 0; k < dof; k++) {
5097: tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5098: }
5099: }
5100: }
5101: }
5102: else {
5103: /* copy this column as is */
5104: for (r = 0; r < numIndices; r++) {
5105: for (c = 0; c < dof; c++) {
5106: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5107: }
5108: }
5109: }
5110: oldOff += dof;
5111: }
5112: }
5113: }
5114: else {
5115: PetscInt oldOff = 0;
5116: for (p = 0; p < numPoints; p++) {
5117: PetscInt cStart = newPointOffsets[0][p];
5118: PetscInt b = points[2 * p];
5119: PetscInt c, r, k;
5120: PetscInt dof;
5122: PetscSectionGetDof(section,b,&dof);
5123: if (!dof) {
5124: continue;
5125: }
5126: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5127: PetscInt nCols = newPointOffsets[0][p+1]-cStart;
5128: const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5130: for (r = 0; r < numIndices; r++) {
5131: for (c = 0; c < nCols; c++) {
5132: for (k = 0; k < dof; k++) {
5133: tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5134: }
5135: }
5136: }
5137: }
5138: else {
5139: /* copy this column as is */
5140: for (r = 0; r < numIndices; r++) {
5141: for (c = 0; c < dof; c++) {
5142: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5143: }
5144: }
5145: }
5146: oldOff += dof;
5147: }
5148: }
5150: if (multiplyLeft) {
5151: DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5152: PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5153: /* multiply constraints transpose on the left */
5154: if (numFields) {
5155: for (f = 0; f < numFields; f++) {
5156: PetscInt oldOff = offsets[f];
5158: for (p = 0; p < numPoints; p++) {
5159: PetscInt rStart = newPointOffsets[f][p];
5160: PetscInt b = points[2 * p];
5161: PetscInt c, r, k;
5162: PetscInt dof;
5164: PetscSectionGetFieldDof(section,b,f,&dof);
5165: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5166: PetscInt nRows = newPointOffsets[f][p+1]-rStart;
5167: const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5169: for (r = 0; r < nRows; r++) {
5170: for (c = 0; c < newNumIndices; c++) {
5171: for (k = 0; k < dof; k++) {
5172: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5173: }
5174: }
5175: }
5176: }
5177: else {
5178: /* copy this row as is */
5179: for (r = 0; r < dof; r++) {
5180: for (c = 0; c < newNumIndices; c++) {
5181: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5182: }
5183: }
5184: }
5185: oldOff += dof;
5186: }
5187: }
5188: }
5189: else {
5190: PetscInt oldOff = 0;
5192: for (p = 0; p < numPoints; p++) {
5193: PetscInt rStart = newPointOffsets[0][p];
5194: PetscInt b = points[2 * p];
5195: PetscInt c, r, k;
5196: PetscInt dof;
5198: PetscSectionGetDof(section,b,&dof);
5199: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5200: PetscInt nRows = newPointOffsets[0][p+1]-rStart;
5201: const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5203: for (r = 0; r < nRows; r++) {
5204: for (c = 0; c < newNumIndices; c++) {
5205: for (k = 0; k < dof; k++) {
5206: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5207: }
5208: }
5209: }
5210: }
5211: else {
5212: /* copy this row as is */
5213: for (r = 0; r < dof; r++) {
5214: for (c = 0; c < newNumIndices; c++) {
5215: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5216: }
5217: }
5218: }
5219: oldOff += dof;
5220: }
5221: }
5223: DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5224: }
5225: else {
5226: newValues = tmpValues;
5227: }
5228: }
5230: /* clean up */
5231: DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
5232: DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
5234: if (numFields) {
5235: for (f = 0; f < numFields; f++) {
5236: DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
5237: DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
5238: DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
5239: }
5240: }
5241: else {
5242: DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
5243: DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
5244: DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
5245: }
5246: ISRestoreIndices(aIS,&anchors);
5248: /* output */
5249: if (outPoints) {
5250: *outPoints = newPoints;
5251: }
5252: else {
5253: DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5254: }
5255: if (outValues) {
5256: *outValues = newValues;
5257: }
5258: for (f = 0; f <= numFields; f++) {
5259: offsets[f] = newOffsets[f];
5260: }
5261: return(0);
5262: }
5264: /*@C
5265: DMPlexGetClosureIndices - Get the global indices in a vector v for all points in the closure of the given point
5267: Not collective
5269: Input Parameters:
5270: + dm - The DM
5271: . section - The section describing the layout in v, or NULL to use the default section
5272: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5273: - point - The mesh point
5275: Output parameters:
5276: + numIndices - The number of indices
5277: . indices - The indices
5278: - outOffsets - Field offset if not NULL
5280: Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5282: Level: advanced
5284: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5285: @*/
5286: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5287: {
5288: PetscSection clSection;
5289: IS clPoints;
5290: const PetscInt *clp;
5291: const PetscInt **perms[32] = {NULL};
5292: PetscInt *points = NULL, *pointsNew;
5293: PetscInt numPoints, numPointsNew;
5294: PetscInt offsets[32];
5295: PetscInt Nf, Nind, NindNew, off, globalOff, f, p;
5296: PetscErrorCode ierr;
5304: PetscSectionGetNumFields(section, &Nf);
5305: if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5306: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5307: /* Get points in closure */
5308: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5309: /* Get number of indices and indices per field */
5310: for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5311: PetscInt dof, fdof;
5313: PetscSectionGetDof(section, points[p], &dof);
5314: for (f = 0; f < Nf; ++f) {
5315: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5316: offsets[f+1] += fdof;
5317: }
5318: Nind += dof;
5319: }
5320: for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5321: if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5322: if (!Nf) offsets[1] = Nind;
5323: /* Get dual space symmetries */
5324: for (f = 0; f < PetscMax(1,Nf); f++) {
5325: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5326: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5327: }
5328: /* Correct for hanging node constraints */
5329: {
5330: DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5331: if (numPointsNew) {
5332: for (f = 0; f < PetscMax(1,Nf); f++) {
5333: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5334: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5335: }
5336: for (f = 0; f < PetscMax(1,Nf); f++) {
5337: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5338: else {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5339: }
5340: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5341: numPoints = numPointsNew;
5342: Nind = NindNew;
5343: points = pointsNew;
5344: }
5345: }
5346: /* Calculate indices */
5347: DMGetWorkArray(dm, Nind, PETSC_INT, indices);
5348: if (Nf) {
5349: if (outOffsets) {
5350: PetscInt f;
5352: for (f = 0; f <= Nf; f++) {
5353: outOffsets[f] = offsets[f];
5354: }
5355: }
5356: for (p = 0; p < numPoints; p++) {
5357: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5358: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5359: }
5360: } else {
5361: for (p = 0, off = 0; p < numPoints; p++) {
5362: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5364: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5365: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5366: }
5367: }
5368: /* Cleanup points */
5369: for (f = 0; f < PetscMax(1,Nf); f++) {
5370: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5371: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5372: }
5373: if (numPointsNew) {
5374: DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);
5375: } else {
5376: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5377: }
5378: if (numIndices) *numIndices = Nind;
5379: return(0);
5380: }
5382: /*@C
5383: DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5385: Not collective
5387: Input Parameters:
5388: + dm - The DM
5389: . section - The section describing the layout in v, or NULL to use the default section
5390: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5391: . point - The mesh point
5392: . numIndices - The number of indices
5393: . indices - The indices
5394: - outOffsets - Field offset if not NULL
5396: Level: advanced
5398: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5399: @*/
5400: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5401: {
5407: DMRestoreWorkArray(dm, 0, PETSC_INT, indices);
5408: return(0);
5409: }
5411: /*@C
5412: DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5414: Not collective
5416: Input Parameters:
5417: + dm - The DM
5418: . section - The section describing the layout in v, or NULL to use the default section
5419: . globalSection - The section describing the layout in v, or NULL to use the default global section
5420: . A - The matrix
5421: . point - The sieve point in the DM
5422: . values - The array of values
5423: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5425: Fortran Notes:
5426: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5428: Level: intermediate
5430: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5431: @*/
5432: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5433: {
5434: DM_Plex *mesh = (DM_Plex*) dm->data;
5435: PetscSection clSection;
5436: IS clPoints;
5437: PetscInt *points = NULL, *newPoints;
5438: const PetscInt *clp;
5439: PetscInt *indices;
5440: PetscInt offsets[32];
5441: const PetscInt **perms[32] = {NULL};
5442: const PetscScalar **flips[32] = {NULL};
5443: PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5444: PetscScalar *valCopy = NULL;
5445: PetscScalar *newValues;
5446: PetscErrorCode ierr;
5450: if (!section) {DMGetDefaultSection(dm, §ion);}
5452: if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5455: PetscSectionGetNumFields(section, &numFields);
5456: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5457: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5458: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5459: for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5460: PetscInt fdof;
5462: PetscSectionGetDof(section, points[p], &dof);
5463: for (f = 0; f < numFields; ++f) {
5464: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5465: offsets[f+1] += fdof;
5466: }
5467: numIndices += dof;
5468: }
5469: for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5471: if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5472: /* Get symmetries */
5473: for (f = 0; f < PetscMax(1,numFields); f++) {
5474: if (numFields) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5475: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5476: if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5477: PetscInt foffset = offsets[f];
5479: for (p = 0; p < numPoints; p++) {
5480: PetscInt point = points[2*p], fdof;
5481: const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5483: if (!numFields) {
5484: PetscSectionGetDof(section,point,&fdof);
5485: } else {
5486: PetscSectionGetFieldDof(section,point,f,&fdof);
5487: }
5488: if (flip) {
5489: PetscInt i, j, k;
5491: if (!valCopy) {
5492: DMGetWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5493: for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5494: values = valCopy;
5495: }
5496: for (i = 0; i < fdof; i++) {
5497: PetscScalar fval = flip[i];
5499: for (k = 0; k < numIndices; k++) {
5500: valCopy[numIndices * (foffset + i) + k] *= fval;
5501: valCopy[numIndices * k + (foffset + i)] *= fval;
5502: }
5503: }
5504: }
5505: foffset += fdof;
5506: }
5507: }
5508: }
5509: DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5510: if (newNumPoints) {
5511: if (valCopy) {
5512: DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5513: }
5514: for (f = 0; f < PetscMax(1,numFields); f++) {
5515: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5516: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5517: }
5518: for (f = 0; f < PetscMax(1,numFields); f++) {
5519: if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5520: else {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5521: }
5522: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5523: numPoints = newNumPoints;
5524: numIndices = newNumIndices;
5525: points = newPoints;
5526: values = newValues;
5527: }
5528: DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5529: if (numFields) {
5530: for (p = 0; p < numPoints; p++) {
5531: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5532: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5533: }
5534: } else {
5535: for (p = 0, off = 0; p < numPoints; p++) {
5536: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5537: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5538: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5539: }
5540: }
5541: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5542: MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5543: if (mesh->printFEM > 1) {
5544: PetscInt i;
5545: PetscPrintf(PETSC_COMM_SELF, " Indices:");
5546: for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5547: PetscPrintf(PETSC_COMM_SELF, "\n");
5548: }
5549: if (ierr) {
5550: PetscMPIInt rank;
5551: PetscErrorCode ierr2;
5553: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5554: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5555: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5556: ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5557:
5558: }
5559: for (f = 0; f < PetscMax(1,numFields); f++) {
5560: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5561: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5562: }
5563: if (newNumPoints) {
5564: DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5565: DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5566: }
5567: else {
5568: if (valCopy) {
5569: DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5570: }
5571: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5572: }
5573: DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5574: return(0);
5575: }
5577: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5578: {
5579: DM_Plex *mesh = (DM_Plex*) dmf->data;
5580: PetscInt *fpoints = NULL, *ftotpoints = NULL;
5581: PetscInt *cpoints = NULL;
5582: PetscInt *findices, *cindices;
5583: PetscInt foffsets[32], coffsets[32];
5584: CellRefiner cellRefiner;
5585: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5586: PetscErrorCode ierr;
5591: if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5593: if (!csection) {DMGetDefaultSection(dmc, &csection);}
5595: if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5597: if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5600: PetscSectionGetNumFields(fsection, &numFields);
5601: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5602: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5603: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5604: /* Column indices */
5605: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5606: maxFPoints = numCPoints;
5607: /* Compress out points not in the section */
5608: /* TODO: Squeeze out points with 0 dof as well */
5609: PetscSectionGetChart(csection, &pStart, &pEnd);
5610: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5611: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5612: cpoints[q*2] = cpoints[p];
5613: cpoints[q*2+1] = cpoints[p+1];
5614: ++q;
5615: }
5616: }
5617: numCPoints = q;
5618: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5619: PetscInt fdof;
5621: PetscSectionGetDof(csection, cpoints[p], &dof);
5622: if (!dof) continue;
5623: for (f = 0; f < numFields; ++f) {
5624: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5625: coffsets[f+1] += fdof;
5626: }
5627: numCIndices += dof;
5628: }
5629: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5630: /* Row indices */
5631: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5632: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5633: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5634: for (r = 0, q = 0; r < numSubcells; ++r) {
5635: /* TODO Map from coarse to fine cells */
5636: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5637: /* Compress out points not in the section */
5638: PetscSectionGetChart(fsection, &pStart, &pEnd);
5639: for (p = 0; p < numFPoints*2; p += 2) {
5640: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5641: PetscSectionGetDof(fsection, fpoints[p], &dof);
5642: if (!dof) continue;
5643: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5644: if (s < q) continue;
5645: ftotpoints[q*2] = fpoints[p];
5646: ftotpoints[q*2+1] = fpoints[p+1];
5647: ++q;
5648: }
5649: }
5650: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5651: }
5652: numFPoints = q;
5653: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5654: PetscInt fdof;
5656: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5657: if (!dof) continue;
5658: for (f = 0; f < numFields; ++f) {
5659: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5660: foffsets[f+1] += fdof;
5661: }
5662: numFIndices += dof;
5663: }
5664: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5666: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5667: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5668: DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5669: DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5670: if (numFields) {
5671: const PetscInt **permsF[32] = {NULL};
5672: const PetscInt **permsC[32] = {NULL};
5674: for (f = 0; f < numFields; f++) {
5675: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5676: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5677: }
5678: for (p = 0; p < numFPoints; p++) {
5679: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5680: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5681: }
5682: for (p = 0; p < numCPoints; p++) {
5683: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5684: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5685: }
5686: for (f = 0; f < numFields; f++) {
5687: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5688: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5689: }
5690: } else {
5691: const PetscInt **permsF = NULL;
5692: const PetscInt **permsC = NULL;
5694: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5695: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5696: for (p = 0, off = 0; p < numFPoints; p++) {
5697: const PetscInt *perm = permsF ? permsF[p] : NULL;
5699: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5700: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5701: }
5702: for (p = 0, off = 0; p < numCPoints; p++) {
5703: const PetscInt *perm = permsC ? permsC[p] : NULL;
5705: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5706: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5707: }
5708: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5709: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5710: }
5711: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5712: /* TODO: flips */
5713: MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5714: if (ierr) {
5715: PetscMPIInt rank;
5716: PetscErrorCode ierr2;
5718: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5719: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5720: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5721: ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5722: ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5723:
5724: }
5725: DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5726: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5727: DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5728: DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5729: return(0);
5730: }
5732: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5733: {
5734: PetscInt *fpoints = NULL, *ftotpoints = NULL;
5735: PetscInt *cpoints = NULL;
5736: PetscInt foffsets[32], coffsets[32];
5737: CellRefiner cellRefiner;
5738: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5744: if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5746: if (!csection) {DMGetDefaultSection(dmc, &csection);}
5748: if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5750: if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5752: PetscSectionGetNumFields(fsection, &numFields);
5753: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5754: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5755: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5756: /* Column indices */
5757: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5758: maxFPoints = numCPoints;
5759: /* Compress out points not in the section */
5760: /* TODO: Squeeze out points with 0 dof as well */
5761: PetscSectionGetChart(csection, &pStart, &pEnd);
5762: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5763: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5764: cpoints[q*2] = cpoints[p];
5765: cpoints[q*2+1] = cpoints[p+1];
5766: ++q;
5767: }
5768: }
5769: numCPoints = q;
5770: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5771: PetscInt fdof;
5773: PetscSectionGetDof(csection, cpoints[p], &dof);
5774: if (!dof) continue;
5775: for (f = 0; f < numFields; ++f) {
5776: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5777: coffsets[f+1] += fdof;
5778: }
5779: numCIndices += dof;
5780: }
5781: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5782: /* Row indices */
5783: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5784: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5785: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5786: for (r = 0, q = 0; r < numSubcells; ++r) {
5787: /* TODO Map from coarse to fine cells */
5788: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5789: /* Compress out points not in the section */
5790: PetscSectionGetChart(fsection, &pStart, &pEnd);
5791: for (p = 0; p < numFPoints*2; p += 2) {
5792: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5793: PetscSectionGetDof(fsection, fpoints[p], &dof);
5794: if (!dof) continue;
5795: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5796: if (s < q) continue;
5797: ftotpoints[q*2] = fpoints[p];
5798: ftotpoints[q*2+1] = fpoints[p+1];
5799: ++q;
5800: }
5801: }
5802: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5803: }
5804: numFPoints = q;
5805: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5806: PetscInt fdof;
5808: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5809: if (!dof) continue;
5810: for (f = 0; f < numFields; ++f) {
5811: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5812: foffsets[f+1] += fdof;
5813: }
5814: numFIndices += dof;
5815: }
5816: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5818: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5819: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5820: if (numFields) {
5821: const PetscInt **permsF[32] = {NULL};
5822: const PetscInt **permsC[32] = {NULL};
5824: for (f = 0; f < numFields; f++) {
5825: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5826: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5827: }
5828: for (p = 0; p < numFPoints; p++) {
5829: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5830: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5831: }
5832: for (p = 0; p < numCPoints; p++) {
5833: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5834: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5835: }
5836: for (f = 0; f < numFields; f++) {
5837: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5838: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5839: }
5840: } else {
5841: const PetscInt **permsF = NULL;
5842: const PetscInt **permsC = NULL;
5844: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5845: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5846: for (p = 0, off = 0; p < numFPoints; p++) {
5847: const PetscInt *perm = permsF ? permsF[p] : NULL;
5849: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5850: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5851: }
5852: for (p = 0, off = 0; p < numCPoints; p++) {
5853: const PetscInt *perm = permsC ? permsC[p] : NULL;
5855: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5856: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5857: }
5858: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5859: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5860: }
5861: DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5862: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5863: return(0);
5864: }
5866: /*@
5867: DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
5869: Input Parameter:
5870: . dm - The DMPlex object
5872: Output Parameters:
5873: + cMax - The first hybrid cell
5874: . fMax - The first hybrid face
5875: . eMax - The first hybrid edge
5876: - vMax - The first hybrid vertex
5878: Level: developer
5880: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5881: @*/
5882: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5883: {
5884: DM_Plex *mesh = (DM_Plex*) dm->data;
5885: PetscInt dim;
5890: DMGetDimension(dm, &dim);
5891: if (cMax) *cMax = mesh->hybridPointMax[dim];
5892: if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5893: if (eMax) *eMax = mesh->hybridPointMax[1];
5894: if (vMax) *vMax = mesh->hybridPointMax[0];
5895: return(0);
5896: }
5898: /*@
5899: DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
5901: Input Parameters:
5902: . dm - The DMPlex object
5903: . cMax - The first hybrid cell
5904: . fMax - The first hybrid face
5905: . eMax - The first hybrid edge
5906: - vMax - The first hybrid vertex
5908: Level: developer
5910: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5911: @*/
5912: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5913: {
5914: DM_Plex *mesh = (DM_Plex*) dm->data;
5915: PetscInt dim;
5920: DMGetDimension(dm, &dim);
5921: if (cMax >= 0) mesh->hybridPointMax[dim] = cMax;
5922: if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5923: if (eMax >= 0) mesh->hybridPointMax[1] = eMax;
5924: if (vMax >= 0) mesh->hybridPointMax[0] = vMax;
5925: return(0);
5926: }
5928: /*@C
5929: DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
5931: Input Parameter:
5932: . dm - The DMPlex object
5934: Output Parameter:
5935: . cellHeight - The height of a cell
5937: Level: developer
5939: .seealso DMPlexSetVTKCellHeight()
5940: @*/
5941: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5942: {
5943: DM_Plex *mesh = (DM_Plex*) dm->data;
5948: *cellHeight = mesh->vtkCellHeight;
5949: return(0);
5950: }
5952: /*@C
5953: DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
5955: Input Parameters:
5956: + dm - The DMPlex object
5957: - cellHeight - The height of a cell
5959: Level: developer
5961: .seealso DMPlexGetVTKCellHeight()
5962: @*/
5963: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5964: {
5965: DM_Plex *mesh = (DM_Plex*) dm->data;
5969: mesh->vtkCellHeight = cellHeight;
5970: return(0);
5971: }
5973: /* We can easily have a form that takes an IS instead */
5974: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5975: {
5976: PetscSection section, globalSection;
5977: PetscInt *numbers, p;
5981: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
5982: PetscSectionSetChart(section, pStart, pEnd);
5983: for (p = pStart; p < pEnd; ++p) {
5984: PetscSectionSetDof(section, p, 1);
5985: }
5986: PetscSectionSetUp(section);
5987: PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
5988: PetscMalloc1(pEnd - pStart, &numbers);
5989: for (p = pStart; p < pEnd; ++p) {
5990: PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5991: if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5992: else numbers[p-pStart] += shift;
5993: }
5994: ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5995: if (globalSize) {
5996: PetscLayout layout;
5997: PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
5998: PetscLayoutGetSize(layout, globalSize);
5999: PetscLayoutDestroy(&layout);
6000: }
6001: PetscSectionDestroy(§ion);
6002: PetscSectionDestroy(&globalSection);
6003: return(0);
6004: }
6006: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6007: {
6008: PetscInt cellHeight, cStart, cEnd, cMax;
6012: DMPlexGetVTKCellHeight(dm, &cellHeight);
6013: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6014: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6015: if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6016: DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6017: return(0);
6018: }
6020: /*@C
6021: DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6023: Input Parameter:
6024: . dm - The DMPlex object
6026: Output Parameter:
6027: . globalCellNumbers - Global cell numbers for all cells on this process
6029: Level: developer
6031: .seealso DMPlexGetVertexNumbering()
6032: @*/
6033: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6034: {
6035: DM_Plex *mesh = (DM_Plex*) dm->data;
6040: if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6041: *globalCellNumbers = mesh->globalCellNumbers;
6042: return(0);
6043: }
6045: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6046: {
6047: PetscInt vStart, vEnd, vMax;
6052: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6053: DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6054: if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6055: DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6056: return(0);
6057: }
6059: /*@C
6060: DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process
6062: Input Parameter:
6063: . dm - The DMPlex object
6065: Output Parameter:
6066: . globalVertexNumbers - Global vertex numbers for all vertices on this process
6068: Level: developer
6070: .seealso DMPlexGetCellNumbering()
6071: @*/
6072: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6073: {
6074: DM_Plex *mesh = (DM_Plex*) dm->data;
6079: if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6080: *globalVertexNumbers = mesh->globalVertexNumbers;
6081: return(0);
6082: }
6084: /*@C
6085: DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6087: Input Parameter:
6088: . dm - The DMPlex object
6090: Output Parameter:
6091: . globalPointNumbers - Global numbers for all points on this process
6093: Level: developer
6095: .seealso DMPlexGetCellNumbering()
6096: @*/
6097: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6098: {
6099: IS nums[4];
6100: PetscInt depths[4];
6101: PetscInt depth, d, shift = 0;
6106: DMPlexGetDepth(dm, &depth);
6107: /* For unstratified meshes use dim instead of depth */
6108: if (depth < 0) {DMGetDimension(dm, &depth);}
6109: depths[0] = depth; depths[1] = 0;
6110: for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6111: for (d = 0; d <= depth; ++d) {
6112: PetscInt pStart, pEnd, gsize;
6114: DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6115: DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6116: shift += gsize;
6117: }
6118: ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6119: for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6120: return(0);
6121: }
6124: /*@
6125: DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6127: Input Parameter:
6128: . dm - The DMPlex object
6130: Output Parameter:
6131: . ranks - The rank field
6133: Options Database Keys:
6134: . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6136: Level: intermediate
6138: .seealso: DMView()
6139: @*/
6140: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6141: {
6142: DM rdm;
6143: PetscDS prob;
6144: PetscFE fe;
6145: PetscScalar *r;
6146: PetscMPIInt rank;
6147: PetscInt dim, cStart, cEnd, c;
6151: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6152: DMClone(dm, &rdm);
6153: DMGetDimension(rdm, &dim);
6154: PetscFECreateDefault(rdm, dim, 1, PETSC_TRUE, NULL, -1, &fe);
6155: PetscObjectSetName((PetscObject) fe, "rank");
6156: DMGetDS(rdm, &prob);
6157: PetscDSSetDiscretization(prob, 0, (PetscObject) fe);
6158: PetscFEDestroy(&fe);
6159: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6160: DMCreateGlobalVector(rdm, ranks);
6161: PetscObjectSetName((PetscObject) *ranks, "partition");
6162: VecGetArray(*ranks, &r);
6163: for (c = cStart; c < cEnd; ++c) {
6164: PetscScalar *lr;
6166: DMPlexPointGlobalRef(rdm, c, r, &lr);
6167: *lr = rank;
6168: }
6169: VecRestoreArray(*ranks, &r);
6170: DMDestroy(&rdm);
6171: return(0);
6172: }
6174: /*@
6175: DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6177: Input Parameter:
6178: . dm - The DMPlex object
6180: Note: This is a useful diagnostic when creating meshes programmatically.
6182: Level: developer
6184: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6185: @*/
6186: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6187: {
6188: PetscSection coneSection, supportSection;
6189: const PetscInt *cone, *support;
6190: PetscInt coneSize, c, supportSize, s;
6191: PetscInt pStart, pEnd, p, csize, ssize;
6192: PetscErrorCode ierr;
6196: DMPlexGetConeSection(dm, &coneSection);
6197: DMPlexGetSupportSection(dm, &supportSection);
6198: /* Check that point p is found in the support of its cone points, and vice versa */
6199: DMPlexGetChart(dm, &pStart, &pEnd);
6200: for (p = pStart; p < pEnd; ++p) {
6201: DMPlexGetConeSize(dm, p, &coneSize);
6202: DMPlexGetCone(dm, p, &cone);
6203: for (c = 0; c < coneSize; ++c) {
6204: PetscBool dup = PETSC_FALSE;
6205: PetscInt d;
6206: for (d = c-1; d >= 0; --d) {
6207: if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6208: }
6209: DMPlexGetSupportSize(dm, cone[c], &supportSize);
6210: DMPlexGetSupport(dm, cone[c], &support);
6211: for (s = 0; s < supportSize; ++s) {
6212: if (support[s] == p) break;
6213: }
6214: if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6215: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6216: for (s = 0; s < coneSize; ++s) {
6217: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6218: }
6219: PetscPrintf(PETSC_COMM_SELF, "\n");
6220: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6221: for (s = 0; s < supportSize; ++s) {
6222: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6223: }
6224: PetscPrintf(PETSC_COMM_SELF, "\n");
6225: if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6226: else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6227: }
6228: }
6229: DMPlexGetSupportSize(dm, p, &supportSize);
6230: DMPlexGetSupport(dm, p, &support);
6231: for (s = 0; s < supportSize; ++s) {
6232: DMPlexGetConeSize(dm, support[s], &coneSize);
6233: DMPlexGetCone(dm, support[s], &cone);
6234: for (c = 0; c < coneSize; ++c) {
6235: if (cone[c] == p) break;
6236: }
6237: if (c >= coneSize) {
6238: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6239: for (c = 0; c < supportSize; ++c) {
6240: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6241: }
6242: PetscPrintf(PETSC_COMM_SELF, "\n");
6243: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6244: for (c = 0; c < coneSize; ++c) {
6245: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6246: }
6247: PetscPrintf(PETSC_COMM_SELF, "\n");
6248: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6249: }
6250: }
6251: }
6252: PetscSectionGetStorageSize(coneSection, &csize);
6253: PetscSectionGetStorageSize(supportSection, &ssize);
6254: if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6255: return(0);
6256: }
6258: /*@
6259: DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6261: Input Parameters:
6262: + dm - The DMPlex object
6263: . isSimplex - Are the cells simplices or tensor products
6264: - cellHeight - Normally 0
6266: Note: This is a useful diagnostic when creating meshes programmatically.
6268: Level: developer
6270: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6271: @*/
6272: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6273: {
6274: PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6279: DMGetDimension(dm, &dim);
6280: switch (dim) {
6281: case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6282: case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6283: case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6284: default:
6285: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6286: }
6287: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6288: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6289: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6290: cMax = cMax >= 0 ? cMax : cEnd;
6291: for (c = cStart; c < cMax; ++c) {
6292: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6294: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6295: for (cl = 0; cl < closureSize*2; cl += 2) {
6296: const PetscInt p = closure[cl];
6297: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6298: }
6299: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6300: if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D", c, coneSize, numCorners);
6301: }
6302: for (c = cMax; c < cEnd; ++c) {
6303: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6305: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6306: for (cl = 0; cl < closureSize*2; cl += 2) {
6307: const PetscInt p = closure[cl];
6308: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6309: }
6310: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6311: if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has %D vertices > %D", c, coneSize, numHybridCorners);
6312: }
6313: return(0);
6314: }
6316: /*@
6317: DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6319: Input Parameters:
6320: + dm - The DMPlex object
6321: . isSimplex - Are the cells simplices or tensor products
6322: - cellHeight - Normally 0
6324: Note: This is a useful diagnostic when creating meshes programmatically.
6326: Level: developer
6328: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6329: @*/
6330: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6331: {
6332: PetscInt pMax[4];
6333: PetscInt dim, vStart, vEnd, cStart, cEnd, c, h;
6338: DMGetDimension(dm, &dim);
6339: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6340: DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6341: for (h = cellHeight; h < dim; ++h) {
6342: DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6343: for (c = cStart; c < cEnd; ++c) {
6344: const PetscInt *cone, *ornt, *faces;
6345: PetscInt numFaces, faceSize, coneSize,f;
6346: PetscInt *closure = NULL, closureSize, cl, numCorners = 0;
6348: if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6349: DMPlexGetConeSize(dm, c, &coneSize);
6350: DMPlexGetCone(dm, c, &cone);
6351: DMPlexGetConeOrientation(dm, c, &ornt);
6352: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6353: for (cl = 0; cl < closureSize*2; cl += 2) {
6354: const PetscInt p = closure[cl];
6355: if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6356: }
6357: DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6358: if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6359: for (f = 0; f < numFaces; ++f) {
6360: PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6362: DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6363: for (cl = 0; cl < fclosureSize*2; cl += 2) {
6364: const PetscInt p = fclosure[cl];
6365: if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6366: }
6367: 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);
6368: for (v = 0; v < fnumCorners; ++v) {
6369: 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]);
6370: }
6371: DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6372: }
6373: DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6374: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6375: }
6376: }
6377: return(0);
6378: }
6380: /* Pointwise interpolation
6381: Just code FEM for now
6382: u^f = I u^c
6383: sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6384: u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6385: I_{ij} = psi^f_i phi^c_j
6386: */
6387: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6388: {
6389: PetscSection gsc, gsf;
6390: PetscInt m, n;
6391: void *ctx;
6392: DM cdm;
6393: PetscBool regular;
6397: DMGetDefaultGlobalSection(dmFine, &gsf);
6398: PetscSectionGetConstrainedStorageSize(gsf, &m);
6399: DMGetDefaultGlobalSection(dmCoarse, &gsc);
6400: PetscSectionGetConstrainedStorageSize(gsc, &n);
6402: MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6403: MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6404: MatSetType(*interpolation, dmCoarse->mattype);
6405: DMGetApplicationContext(dmFine, &ctx);
6407: DMGetCoarseDM(dmFine, &cdm);
6408: DMPlexGetRegularRefinement(dmFine, ®ular);
6409: if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6410: else {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6411: MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6412: /* Use naive scaling */
6413: DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6414: return(0);
6415: }
6417: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6418: {
6420: VecScatter ctx;
6423: DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6424: MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6425: VecScatterDestroy(&ctx);
6426: return(0);
6427: }
6429: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6430: {
6431: PetscSection section;
6432: IS *bcPoints, *bcComps;
6433: PetscBool *isFE;
6434: PetscInt *bcFields, *numComp, *numDof;
6435: PetscInt depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6436: PetscInt cStart, cEnd, cEndInterior;
6440: DMGetNumFields(dm, &numFields);
6441: if (!numFields) return(0);
6442: /* FE and FV boundary conditions are handled slightly differently */
6443: PetscMalloc1(numFields, &isFE);
6444: for (f = 0; f < numFields; ++f) {
6445: PetscObject obj;
6446: PetscClassId id;
6448: DMGetField(dm, f, &obj);
6449: PetscObjectGetClassId(obj, &id);
6450: if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;}
6451: else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6452: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6453: }
6454: /* Allocate boundary point storage for FEM boundaries */
6455: DMPlexGetDepth(dm, &depth);
6456: DMGetDimension(dm, &dim);
6457: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6458: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6459: PetscDSGetNumBoundary(dm->prob, &numBd);
6460: for (bd = 0; bd < numBd; ++bd) {
6461: PetscInt field;
6462: DMBoundaryConditionType type;
6463: const char *labelName;
6464: DMLabel label;
6466: PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6467: DMGetLabel(dm,labelName,&label);
6468: if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6469: }
6470: /* Add ghost cell boundaries for FVM */
6471: for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6472: PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6473: /* Constrain ghost cells for FV */
6474: for (f = 0; f < numFields; ++f) {
6475: PetscInt *newidx, c;
6477: if (isFE[f] || cEndInterior < 0) continue;
6478: PetscMalloc1(cEnd-cEndInterior,&newidx);
6479: for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6480: bcFields[bc] = f;
6481: ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6482: }
6483: /* Handle FEM Dirichlet boundaries */
6484: for (bd = 0; bd < numBd; ++bd) {
6485: const char *bdLabel;
6486: DMLabel label;
6487: const PetscInt *comps;
6488: const PetscInt *values;
6489: PetscInt bd2, field, numComps, numValues;
6490: DMBoundaryConditionType type;
6491: PetscBool duplicate = PETSC_FALSE;
6493: PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6494: DMGetLabel(dm, bdLabel, &label);
6495: if (!isFE[field] || !label) continue;
6496: /* Only want to modify label once */
6497: for (bd2 = 0; bd2 < bd; ++bd2) {
6498: const char *bdname;
6499: PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6500: PetscStrcmp(bdname, bdLabel, &duplicate);
6501: if (duplicate) break;
6502: }
6503: if (!duplicate && (isFE[field])) {
6504: /* don't complete cells, which are just present to give orientation to the boundary */
6505: DMPlexLabelComplete(dm, label);
6506: }
6507: /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6508: if (type & DM_BC_ESSENTIAL) {
6509: PetscInt *newidx;
6510: PetscInt n, newn = 0, p, v;
6512: bcFields[bc] = field;
6513: if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6514: for (v = 0; v < numValues; ++v) {
6515: IS tmp;
6516: const PetscInt *idx;
6518: DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6519: if (!tmp) continue;
6520: ISGetLocalSize(tmp, &n);
6521: ISGetIndices(tmp, &idx);
6522: if (isFE[field]) {
6523: for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6524: } else {
6525: for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6526: }
6527: ISRestoreIndices(tmp, &idx);
6528: ISDestroy(&tmp);
6529: }
6530: PetscMalloc1(newn,&newidx);
6531: newn = 0;
6532: for (v = 0; v < numValues; ++v) {
6533: IS tmp;
6534: const PetscInt *idx;
6536: DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6537: if (!tmp) continue;
6538: ISGetLocalSize(tmp, &n);
6539: ISGetIndices(tmp, &idx);
6540: if (isFE[field]) {
6541: for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6542: } else {
6543: for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6544: }
6545: ISRestoreIndices(tmp, &idx);
6546: ISDestroy(&tmp);
6547: }
6548: ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6549: }
6550: }
6551: /* Handle discretization */
6552: PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6553: for (f = 0; f < numFields; ++f) {
6554: PetscObject obj;
6556: DMGetField(dm, f, &obj);
6557: if (isFE[f]) {
6558: PetscFE fe = (PetscFE) obj;
6559: const PetscInt *numFieldDof;
6560: PetscInt d;
6562: PetscFEGetNumComponents(fe, &numComp[f]);
6563: PetscFEGetNumDof(fe, &numFieldDof);
6564: for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6565: } else {
6566: PetscFV fv = (PetscFV) obj;
6568: PetscFVGetNumComponents(fv, &numComp[f]);
6569: numDof[f*(dim+1)+dim] = numComp[f];
6570: }
6571: }
6572: for (f = 0; f < numFields; ++f) {
6573: PetscInt d;
6574: for (d = 1; d < dim; ++d) {
6575: if ((numDof[f*(dim+1)+d] > 0) && (depth < dim)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces.");
6576: }
6577: }
6578: DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, §ion);
6579: for (f = 0; f < numFields; ++f) {
6580: PetscFE fe;
6581: const char *name;
6583: DMGetField(dm, f, (PetscObject *) &fe);
6584: PetscObjectGetName((PetscObject) fe, &name);
6585: PetscSectionSetFieldName(section, f, name);
6586: }
6587: DMSetDefaultSection(dm, section);
6588: PetscSectionDestroy(§ion);
6589: for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6590: PetscFree3(bcFields,bcPoints,bcComps);
6591: PetscFree2(numComp,numDof);
6592: PetscFree(isFE);
6593: return(0);
6594: }
6596: /*@
6597: DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6599: Input Parameter:
6600: . dm - The DMPlex object
6602: Output Parameter:
6603: . regular - The flag
6605: Level: intermediate
6607: .seealso: DMPlexSetRegularRefinement()
6608: @*/
6609: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6610: {
6614: *regular = ((DM_Plex *) dm->data)->regularRefinement;
6615: return(0);
6616: }
6618: /*@
6619: DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6621: Input Parameters:
6622: + dm - The DMPlex object
6623: - regular - The flag
6625: Level: intermediate
6627: .seealso: DMPlexGetRegularRefinement()
6628: @*/
6629: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6630: {
6633: ((DM_Plex *) dm->data)->regularRefinement = regular;
6634: return(0);
6635: }
6637: /* anchors */
6638: /*@
6639: DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to
6640: call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
6642: not collective
6644: Input Parameters:
6645: . dm - The DMPlex object
6647: Output Parameters:
6648: + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
6649: - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
6652: Level: intermediate
6654: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6655: @*/
6656: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6657: {
6658: DM_Plex *plex = (DM_Plex *)dm->data;
6663: if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6664: if (anchorSection) *anchorSection = plex->anchorSection;
6665: if (anchorIS) *anchorIS = plex->anchorIS;
6666: return(0);
6667: }
6669: /*@
6670: DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions,
6671: when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
6672: point's degrees of freedom to be a linear combination of other points' degrees of freedom.
6674: After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
6675: DMGetConstraints() and filling in the entries in the constraint matrix.
6677: collective on dm
6679: Input Parameters:
6680: + dm - The DMPlex object
6681: . 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).
6682: - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative).
6684: The reference counts of anchorSection and anchorIS are incremented.
6686: Level: intermediate
6688: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6689: @*/
6690: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6691: {
6692: DM_Plex *plex = (DM_Plex *)dm->data;
6693: PetscMPIInt result;
6698: if (anchorSection) {
6700: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6701: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6702: }
6703: if (anchorIS) {
6705: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6706: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6707: }
6709: PetscObjectReference((PetscObject)anchorSection);
6710: PetscSectionDestroy(&plex->anchorSection);
6711: plex->anchorSection = anchorSection;
6713: PetscObjectReference((PetscObject)anchorIS);
6714: ISDestroy(&plex->anchorIS);
6715: plex->anchorIS = anchorIS;
6717: #if defined(PETSC_USE_DEBUG)
6718: if (anchorIS && anchorSection) {
6719: PetscInt size, a, pStart, pEnd;
6720: const PetscInt *anchors;
6722: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6723: ISGetLocalSize(anchorIS,&size);
6724: ISGetIndices(anchorIS,&anchors);
6725: for (a = 0; a < size; a++) {
6726: PetscInt p;
6728: p = anchors[a];
6729: if (p >= pStart && p < pEnd) {
6730: PetscInt dof;
6732: PetscSectionGetDof(anchorSection,p,&dof);
6733: if (dof) {
6734: PetscErrorCode ierr2;
6736: ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6737: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6738: }
6739: }
6740: }
6741: ISRestoreIndices(anchorIS,&anchors);
6742: }
6743: #endif
6744: /* reset the generic constraints */
6745: DMSetDefaultConstraints(dm,NULL,NULL);
6746: return(0);
6747: }
6749: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6750: {
6751: PetscSection anchorSection;
6752: PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
6757: DMPlexGetAnchors(dm,&anchorSection,NULL);
6758: PetscSectionCreate(PETSC_COMM_SELF,cSec);
6759: PetscSectionGetNumFields(section,&numFields);
6760: if (numFields) {
6761: PetscInt f;
6762: PetscSectionSetNumFields(*cSec,numFields);
6764: for (f = 0; f < numFields; f++) {
6765: PetscInt numComp;
6767: PetscSectionGetFieldComponents(section,f,&numComp);
6768: PetscSectionSetFieldComponents(*cSec,f,numComp);
6769: }
6770: }
6771: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6772: PetscSectionGetChart(section,&sStart,&sEnd);
6773: pStart = PetscMax(pStart,sStart);
6774: pEnd = PetscMin(pEnd,sEnd);
6775: pEnd = PetscMax(pStart,pEnd);
6776: PetscSectionSetChart(*cSec,pStart,pEnd);
6777: for (p = pStart; p < pEnd; p++) {
6778: PetscSectionGetDof(anchorSection,p,&dof);
6779: if (dof) {
6780: PetscSectionGetDof(section,p,&dof);
6781: PetscSectionSetDof(*cSec,p,dof);
6782: for (f = 0; f < numFields; f++) {
6783: PetscSectionGetFieldDof(section,p,f,&dof);
6784: PetscSectionSetFieldDof(*cSec,p,f,dof);
6785: }
6786: }
6787: }
6788: PetscSectionSetUp(*cSec);
6789: return(0);
6790: }
6792: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6793: {
6794: PetscSection aSec;
6795: PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6796: const PetscInt *anchors;
6797: PetscInt numFields, f;
6798: IS aIS;
6803: PetscSectionGetStorageSize(cSec, &m);
6804: PetscSectionGetStorageSize(section, &n);
6805: MatCreate(PETSC_COMM_SELF,cMat);
6806: MatSetSizes(*cMat,m,n,m,n);
6807: MatSetType(*cMat,MATSEQAIJ);
6808: DMPlexGetAnchors(dm,&aSec,&aIS);
6809: ISGetIndices(aIS,&anchors);
6810: /* cSec will be a subset of aSec and section */
6811: PetscSectionGetChart(cSec,&pStart,&pEnd);
6812: PetscMalloc1(m+1,&i);
6813: i[0] = 0;
6814: PetscSectionGetNumFields(section,&numFields);
6815: for (p = pStart; p < pEnd; p++) {
6816: PetscInt rDof, rOff, r;
6818: PetscSectionGetDof(aSec,p,&rDof);
6819: if (!rDof) continue;
6820: PetscSectionGetOffset(aSec,p,&rOff);
6821: if (numFields) {
6822: for (f = 0; f < numFields; f++) {
6823: annz = 0;
6824: for (r = 0; r < rDof; r++) {
6825: a = anchors[rOff + r];
6826: PetscSectionGetFieldDof(section,a,f,&aDof);
6827: annz += aDof;
6828: }
6829: PetscSectionGetFieldDof(cSec,p,f,&dof);
6830: PetscSectionGetFieldOffset(cSec,p,f,&off);
6831: for (q = 0; q < dof; q++) {
6832: i[off + q + 1] = i[off + q] + annz;
6833: }
6834: }
6835: }
6836: else {
6837: annz = 0;
6838: for (q = 0; q < dof; q++) {
6839: a = anchors[off + q];
6840: PetscSectionGetDof(section,a,&aDof);
6841: annz += aDof;
6842: }
6843: PetscSectionGetDof(cSec,p,&dof);
6844: PetscSectionGetOffset(cSec,p,&off);
6845: for (q = 0; q < dof; q++) {
6846: i[off + q + 1] = i[off + q] + annz;
6847: }
6848: }
6849: }
6850: nnz = i[m];
6851: PetscMalloc1(nnz,&j);
6852: offset = 0;
6853: for (p = pStart; p < pEnd; p++) {
6854: if (numFields) {
6855: for (f = 0; f < numFields; f++) {
6856: PetscSectionGetFieldDof(cSec,p,f,&dof);
6857: for (q = 0; q < dof; q++) {
6858: PetscInt rDof, rOff, r;
6859: PetscSectionGetDof(aSec,p,&rDof);
6860: PetscSectionGetOffset(aSec,p,&rOff);
6861: for (r = 0; r < rDof; r++) {
6862: PetscInt s;
6864: a = anchors[rOff + r];
6865: PetscSectionGetFieldDof(section,a,f,&aDof);
6866: PetscSectionGetFieldOffset(section,a,f,&aOff);
6867: for (s = 0; s < aDof; s++) {
6868: j[offset++] = aOff + s;
6869: }
6870: }
6871: }
6872: }
6873: }
6874: else {
6875: PetscSectionGetDof(cSec,p,&dof);
6876: for (q = 0; q < dof; q++) {
6877: PetscInt rDof, rOff, r;
6878: PetscSectionGetDof(aSec,p,&rDof);
6879: PetscSectionGetOffset(aSec,p,&rOff);
6880: for (r = 0; r < rDof; r++) {
6881: PetscInt s;
6883: a = anchors[rOff + r];
6884: PetscSectionGetDof(section,a,&aDof);
6885: PetscSectionGetOffset(section,a,&aOff);
6886: for (s = 0; s < aDof; s++) {
6887: j[offset++] = aOff + s;
6888: }
6889: }
6890: }
6891: }
6892: }
6893: MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
6894: PetscFree(i);
6895: PetscFree(j);
6896: ISRestoreIndices(aIS,&anchors);
6897: return(0);
6898: }
6900: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6901: {
6902: DM_Plex *plex = (DM_Plex *)dm->data;
6903: PetscSection anchorSection, section, cSec;
6904: Mat cMat;
6909: DMPlexGetAnchors(dm,&anchorSection,NULL);
6910: if (anchorSection) {
6911: PetscDS ds;
6912: PetscInt nf;
6914: DMGetDefaultSection(dm,§ion);
6915: DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
6916: DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
6917: DMGetDS(dm,&ds);
6918: PetscDSGetNumFields(ds,&nf);
6919: if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
6920: DMSetDefaultConstraints(dm,cSec,cMat);
6921: PetscSectionDestroy(&cSec);
6922: MatDestroy(&cMat);
6923: }
6924: return(0);
6925: }