Actual source code: plex.c
petsc-3.11.3 2019-06-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>
8: #include <petscdmfield.h>
10: /* Logging support */
11: PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;
13: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
15: /*@
16: DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells.
17: 3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D.
19: Collective
21: Input Parameters:
22: . dm - The DMPlex object
24: Output Parameters:
25: . dmRefined - The refined DMPlex object
27: Note: Returns NULL if the mesh is already a tensor product mesh.
29: Level: intermediate
31: .seealso: DMPlexCreate(), DMPlexSetRefinementUniform()
32: @*/
33: PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined)
34: {
35: PetscInt dim, cMax, fMax, cStart, cEnd, coneSize;
36: CellRefiner cellRefiner;
37: PetscBool lop, allnoop, localized;
38: PetscErrorCode ierr;
43: DMGetDimension(dm, &dim);
44: DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
45: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
46: if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
47: else {
48: DMPlexGetConeSize(dm,cStart,&coneSize);
49: switch (dim) {
50: case 1:
51: cellRefiner = REFINER_NOOP;
52: break;
53: case 2:
54: switch (coneSize) {
55: case 3:
56: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
57: else cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
58: break;
59: case 4:
60: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
61: else cellRefiner = REFINER_NOOP;
62: break;
63: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
64: }
65: break;
66: case 3:
67: switch (coneSize) {
68: case 4:
69: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
70: else cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
71: break;
72: case 5:
73: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
74: else cellRefiner = REFINER_NOOP;
75: break;
76: case 6:
77: if (cMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Simplex2Tensor in 3D with Hybrid mesh not yet done");
78: cellRefiner = REFINER_NOOP;
79: break;
80: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
81: }
82: break;
83: default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
84: }
85: }
86: /* return if we don't need to refine */
87: lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
88: MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
89: if (allnoop) {
90: *dmRefined = NULL;
91: return(0);
92: }
93: DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
94: DMCopyBoundary(dm, *dmRefined);
95: DMGetCoordinatesLocalized(dm, &localized);
96: if (localized) {
97: DMLocalizeCoordinates(*dmRefined);
98: }
99: return(0);
100: }
102: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
103: {
104: PetscInt dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior;
105: PetscInt vcdof[2] = {0,0}, globalvcdof[2];
109: *ft = PETSC_VTK_POINT_FIELD;
110: DMGetDimension(dm, &dim);
111: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
112: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
113: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
114: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
115: PetscSectionGetChart(section, &pStart, &pEnd);
116: if (field >= 0) {
117: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);}
118: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);}
119: } else {
120: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vcdof[0]);}
121: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &vcdof[1]);}
122: }
123: MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
124: if (globalvcdof[0]) {
125: *sStart = vStart;
126: *sEnd = vEnd;
127: if (globalvcdof[0] == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
128: else *ft = PETSC_VTK_POINT_FIELD;
129: } else if (globalvcdof[1]) {
130: *sStart = cStart;
131: *sEnd = cEnd;
132: if (globalvcdof[1] == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
133: else *ft = PETSC_VTK_CELL_FIELD;
134: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
135: return(0);
136: }
138: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
139: {
140: DM dm;
141: PetscSection s;
142: PetscDraw draw, popup;
143: DM cdm;
144: PetscSection coordSection;
145: Vec coordinates;
146: const PetscScalar *coords, *array;
147: PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
148: PetscReal vbound[2], time;
149: PetscBool isnull, flg;
150: PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
151: const char *name;
152: char title[PETSC_MAX_PATH_LEN];
153: PetscErrorCode ierr;
156: PetscViewerDrawGetDraw(viewer, 0, &draw);
157: PetscDrawIsNull(draw, &isnull);
158: if (isnull) return(0);
160: VecGetDM(v, &dm);
161: DMGetCoordinateDim(dm, &dim);
162: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
163: DMGetSection(dm, &s);
164: PetscSectionGetNumFields(s, &Nf);
165: DMGetCoarsenLevel(dm, &level);
166: DMGetCoordinateDM(dm, &cdm);
167: DMGetSection(cdm, &coordSection);
168: DMGetCoordinatesLocal(dm, &coordinates);
169: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
170: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
172: PetscObjectGetName((PetscObject) v, &name);
173: DMGetOutputSequenceNumber(dm, &step, &time);
175: VecGetLocalSize(coordinates, &N);
176: VecGetArrayRead(coordinates, &coords);
177: for (c = 0; c < N; c += dim) {
178: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
179: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
180: }
181: VecRestoreArrayRead(coordinates, &coords);
182: PetscDrawClear(draw);
184: /* Could implement something like DMDASelectFields() */
185: for (f = 0; f < Nf; ++f) {
186: DM fdm = dm;
187: Vec fv = v;
188: IS fis;
189: char prefix[PETSC_MAX_PATH_LEN];
190: const char *fname;
192: PetscSectionGetFieldComponents(s, f, &Nc);
193: PetscSectionGetFieldName(s, f, &fname);
195: if (v->hdr.prefix) {PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));}
196: else {prefix[0] = '\0';}
197: if (Nf > 1) {
198: DMCreateSubDM(dm, 1, &f, &fis, &fdm);
199: VecGetSubVector(v, fis, &fv);
200: PetscStrlcat(prefix, fname,sizeof(prefix));
201: PetscStrlcat(prefix, "_",sizeof(prefix));
202: }
203: for (comp = 0; comp < Nc; ++comp, ++w) {
204: PetscInt nmax = 2;
206: PetscViewerDrawGetDraw(viewer, w, &draw);
207: if (Nc > 1) {PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);}
208: else {PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);}
209: PetscDrawSetTitle(draw, title);
211: /* TODO Get max and min only for this component */
212: PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
213: if (!flg) {
214: VecMin(fv, NULL, &vbound[0]);
215: VecMax(fv, NULL, &vbound[1]);
216: if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
217: }
218: PetscDrawGetPopup(draw, &popup);
219: PetscDrawScalePopup(popup, vbound[0], vbound[1]);
220: PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
222: VecGetArrayRead(fv, &array);
223: for (c = cStart; c < cEnd; ++c) {
224: PetscScalar *coords = NULL, *a = NULL;
225: PetscInt numCoords, color[4] = {-1,-1,-1,-1};
227: DMPlexPointLocalRead(fdm, c, array, &a);
228: if (a) {
229: color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
230: color[1] = color[2] = color[3] = color[0];
231: } else {
232: PetscScalar *vals = NULL;
233: PetscInt numVals, va;
235: DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
236: if (numVals % Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %D does not divide the number of values in the closure %D", Nc, numVals);
237: switch (numVals/Nc) {
238: case 3: /* P1 Triangle */
239: case 4: /* P1 Quadrangle */
240: for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
241: break;
242: case 6: /* P2 Triangle */
243: case 8: /* P2 Quadrangle */
244: for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
245: break;
246: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
247: }
248: DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
249: }
250: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
251: switch (numCoords) {
252: case 6:
253: PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
254: break;
255: case 8:
256: PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
257: PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0]);
258: break;
259: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
260: }
261: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
262: }
263: VecRestoreArrayRead(fv, &array);
264: PetscDrawFlush(draw);
265: PetscDrawPause(draw);
266: PetscDrawSave(draw);
267: }
268: if (Nf > 1) {
269: VecRestoreSubVector(v, fis, &fv);
270: ISDestroy(&fis);
271: DMDestroy(&fdm);
272: }
273: }
274: return(0);
275: }
277: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
278: {
279: DM dm;
280: Vec locv;
281: const char *name;
282: PetscSection section;
283: PetscInt pStart, pEnd;
284: PetscViewerVTKFieldType ft;
285: PetscErrorCode ierr;
288: VecGetDM(v, &dm);
289: DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
290: PetscObjectGetName((PetscObject) v, &name);
291: PetscObjectSetName((PetscObject) locv, name);
292: VecCopy(v, locv);
293: DMGetSection(dm, §ion);
294: DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
295: PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, PETSC_TRUE,(PetscObject) locv);
296: return(0);
297: }
299: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
300: {
301: DM dm;
302: PetscBool isvtk, ishdf5, isdraw, isglvis;
306: VecGetDM(v, &dm);
307: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
308: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
309: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
310: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
311: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
312: if (isvtk || ishdf5 || isdraw || isglvis) {
313: PetscInt i,numFields;
314: PetscObject fe;
315: PetscBool fem = PETSC_FALSE;
316: Vec locv = v;
317: const char *name;
318: PetscInt step;
319: PetscReal time;
321: DMGetNumFields(dm, &numFields);
322: for (i=0; i<numFields; i++) {
323: DMGetField(dm, i, NULL, &fe);
324: if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
325: }
326: if (fem) {
327: DMGetLocalVector(dm, &locv);
328: PetscObjectGetName((PetscObject) v, &name);
329: PetscObjectSetName((PetscObject) locv, name);
330: VecCopy(v, locv);
331: DMGetOutputSequenceNumber(dm, NULL, &time);
332: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
333: }
334: if (isvtk) {
335: VecView_Plex_Local_VTK(locv, viewer);
336: } else if (ishdf5) {
337: #if defined(PETSC_HAVE_HDF5)
338: VecView_Plex_Local_HDF5_Internal(locv, viewer);
339: #else
340: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
341: #endif
342: } else if (isdraw) {
343: VecView_Plex_Local_Draw(locv, viewer);
344: } else if (isglvis) {
345: DMGetOutputSequenceNumber(dm, &step, NULL);
346: PetscViewerGLVisSetSnapId(viewer, step);
347: VecView_GLVis(locv, viewer);
348: }
349: if (fem) {DMRestoreLocalVector(dm, &locv);}
350: } else {
351: PetscBool isseq;
353: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
354: if (isseq) {VecView_Seq(v, viewer);}
355: else {VecView_MPI(v, viewer);}
356: }
357: return(0);
358: }
360: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
361: {
362: DM dm;
363: PetscBool isvtk, ishdf5, isdraw, isglvis;
367: VecGetDM(v, &dm);
368: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
369: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
370: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
371: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
372: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
373: if (isvtk || isdraw || isglvis) {
374: Vec locv;
375: const char *name;
377: DMGetLocalVector(dm, &locv);
378: PetscObjectGetName((PetscObject) v, &name);
379: PetscObjectSetName((PetscObject) locv, name);
380: DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
381: DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
382: VecView_Plex_Local(locv, viewer);
383: DMRestoreLocalVector(dm, &locv);
384: } else if (ishdf5) {
385: #if defined(PETSC_HAVE_HDF5)
386: VecView_Plex_HDF5_Internal(v, viewer);
387: #else
388: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
389: #endif
390: } else {
391: PetscBool isseq;
393: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
394: if (isseq) {VecView_Seq(v, viewer);}
395: else {VecView_MPI(v, viewer);}
396: }
397: return(0);
398: }
400: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
401: {
402: DM dm;
403: MPI_Comm comm;
404: PetscViewerFormat format;
405: Vec v;
406: PetscBool isvtk, ishdf5;
407: PetscErrorCode ierr;
410: VecGetDM(originalv, &dm);
411: PetscObjectGetComm((PetscObject) originalv, &comm);
412: if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
413: PetscViewerGetFormat(viewer, &format);
414: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
415: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
416: if (format == PETSC_VIEWER_NATIVE) {
417: /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
418: /* this need a better fix */
419: if (dm->useNatural) {
420: if (dm->sfNatural) {
421: const char *vecname;
422: PetscInt n, nroots;
424: VecGetLocalSize(originalv, &n);
425: PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
426: if (n == nroots) {
427: DMGetGlobalVector(dm, &v);
428: DMPlexGlobalToNaturalBegin(dm, originalv, v);
429: DMPlexGlobalToNaturalEnd(dm, originalv, v);
430: PetscObjectGetName((PetscObject) originalv, &vecname);
431: PetscObjectSetName((PetscObject) v, vecname);
432: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
433: } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
434: } else v = originalv;
435: } else v = originalv;
437: if (ishdf5) {
438: #if defined(PETSC_HAVE_HDF5)
439: VecView_Plex_HDF5_Native_Internal(v, viewer);
440: #else
441: SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
442: #endif
443: } else if (isvtk) {
444: SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
445: } else {
446: PetscBool isseq;
448: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
449: if (isseq) {VecView_Seq(v, viewer);}
450: else {VecView_MPI(v, viewer);}
451: }
452: if (v != originalv) {DMRestoreGlobalVector(dm, &v);}
453: return(0);
454: }
456: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
457: {
458: DM dm;
459: PetscBool ishdf5;
463: VecGetDM(v, &dm);
464: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
465: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
466: if (ishdf5) {
467: DM dmBC;
468: Vec gv;
469: const char *name;
471: DMGetOutputDM(dm, &dmBC);
472: DMGetGlobalVector(dmBC, &gv);
473: PetscObjectGetName((PetscObject) v, &name);
474: PetscObjectSetName((PetscObject) gv, name);
475: VecLoad_Default(gv, viewer);
476: DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
477: DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
478: DMRestoreGlobalVector(dmBC, &gv);
479: } else {
480: VecLoad_Default(v, viewer);
481: }
482: return(0);
483: }
485: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
486: {
487: DM dm;
488: PetscBool ishdf5;
492: VecGetDM(v, &dm);
493: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
494: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
495: if (ishdf5) {
496: #if defined(PETSC_HAVE_HDF5)
497: VecLoad_Plex_HDF5_Internal(v, viewer);
498: #else
499: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
500: #endif
501: } else {
502: VecLoad_Default(v, viewer);
503: }
504: return(0);
505: }
507: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
508: {
509: DM dm;
510: PetscViewerFormat format;
511: PetscBool ishdf5;
512: PetscErrorCode ierr;
515: VecGetDM(originalv, &dm);
516: if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
517: PetscViewerGetFormat(viewer, &format);
518: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
519: if (format == PETSC_VIEWER_NATIVE) {
520: if (dm->useNatural) {
521: if (dm->sfNatural) {
522: if (ishdf5) {
523: #if defined(PETSC_HAVE_HDF5)
524: Vec v;
525: const char *vecname;
527: DMGetGlobalVector(dm, &v);
528: PetscObjectGetName((PetscObject) originalv, &vecname);
529: PetscObjectSetName((PetscObject) v, vecname);
530: VecLoad_Plex_HDF5_Native_Internal(v, viewer);
531: DMPlexNaturalToGlobalBegin(dm, v, originalv);
532: DMPlexNaturalToGlobalEnd(dm, v, originalv);
533: DMRestoreGlobalVector(dm, &v);
534: #else
535: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
536: #endif
537: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
538: }
539: } else {
540: VecLoad_Default(originalv, viewer);
541: }
542: }
543: return(0);
544: }
546: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
547: {
548: PetscSection coordSection;
549: Vec coordinates;
550: DMLabel depthLabel;
551: const char *name[4];
552: const PetscScalar *a;
553: PetscInt dim, pStart, pEnd, cStart, cEnd, c;
554: PetscErrorCode ierr;
557: DMGetDimension(dm, &dim);
558: DMGetCoordinatesLocal(dm, &coordinates);
559: DMGetCoordinateSection(dm, &coordSection);
560: DMPlexGetDepthLabel(dm, &depthLabel);
561: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
562: PetscSectionGetChart(coordSection, &pStart, &pEnd);
563: VecGetArrayRead(coordinates, &a);
564: name[0] = "vertex";
565: name[1] = "edge";
566: name[dim-1] = "face";
567: name[dim] = "cell";
568: for (c = cStart; c < cEnd; ++c) {
569: PetscInt *closure = NULL;
570: PetscInt closureSize, cl;
572: PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);
573: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
574: PetscViewerASCIIPushTab(viewer);
575: for (cl = 0; cl < closureSize*2; cl += 2) {
576: PetscInt point = closure[cl], depth, dof, off, d, p;
578: if ((point < pStart) || (point >= pEnd)) continue;
579: PetscSectionGetDof(coordSection, point, &dof);
580: if (!dof) continue;
581: DMLabelGetValue(depthLabel, point, &depth);
582: PetscSectionGetOffset(coordSection, point, &off);
583: PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
584: for (p = 0; p < dof/dim; ++p) {
585: PetscViewerASCIIPrintf(viewer, " (");
586: for (d = 0; d < dim; ++d) {
587: if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
588: PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
589: }
590: PetscViewerASCIIPrintf(viewer, ")");
591: }
592: PetscViewerASCIIPrintf(viewer, "\n");
593: }
594: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
595: PetscViewerASCIIPopTab(viewer);
596: }
597: VecRestoreArrayRead(coordinates, &a);
598: return(0);
599: }
601: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
602: {
603: DM_Plex *mesh = (DM_Plex*) dm->data;
604: DM cdm;
605: DMLabel markers;
606: PetscSection coordSection;
607: Vec coordinates;
608: PetscViewerFormat format;
609: PetscErrorCode ierr;
612: DMGetCoordinateDM(dm, &cdm);
613: DMGetSection(cdm, &coordSection);
614: DMGetCoordinatesLocal(dm, &coordinates);
615: PetscViewerGetFormat(viewer, &format);
616: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
617: const char *name;
618: PetscInt dim, cellHeight, maxConeSize, maxSupportSize;
619: PetscInt pStart, pEnd, p;
620: PetscMPIInt rank, size;
622: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
623: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
624: PetscObjectGetName((PetscObject) dm, &name);
625: DMPlexGetChart(dm, &pStart, &pEnd);
626: DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
627: DMGetDimension(dm, &dim);
628: DMPlexGetVTKCellHeight(dm, &cellHeight);
629: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
630: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
631: if (cellHeight) {PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);}
632: PetscViewerASCIIPrintf(viewer, "Supports:\n", name);
633: PetscViewerASCIIPushSynchronized(viewer);
634: PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);
635: for (p = pStart; p < pEnd; ++p) {
636: PetscInt dof, off, s;
638: PetscSectionGetDof(mesh->supportSection, p, &dof);
639: PetscSectionGetOffset(mesh->supportSection, p, &off);
640: for (s = off; s < off+dof; ++s) {
641: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
642: }
643: }
644: PetscViewerFlush(viewer);
645: PetscViewerASCIIPrintf(viewer, "Cones:\n", name);
646: PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);
647: for (p = pStart; p < pEnd; ++p) {
648: PetscInt dof, off, c;
650: PetscSectionGetDof(mesh->coneSection, p, &dof);
651: PetscSectionGetOffset(mesh->coneSection, p, &off);
652: for (c = off; c < off+dof; ++c) {
653: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
654: }
655: }
656: PetscViewerFlush(viewer);
657: PetscViewerASCIIPopSynchronized(viewer);
658: if (coordSection && coordinates) {
659: PetscSectionVecView(coordSection, coordinates, viewer);
660: }
661: DMGetLabel(dm, "marker", &markers);
662: if (markers) {DMLabelView(markers,viewer);}
663: if (size > 1) {
664: PetscSF sf;
666: DMGetPointSF(dm, &sf);
667: PetscSFView(sf, viewer);
668: }
669: PetscViewerFlush(viewer);
670: } else if (format == PETSC_VIEWER_ASCII_LATEX) {
671: const char *name, *color;
672: const char *defcolors[3] = {"gray", "orange", "green"};
673: const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
674: PetscReal scale = 2.0;
675: PetscReal tikzscale = 1.0;
676: PetscBool useNumbers = PETSC_TRUE, useLabels, useColors;
677: double tcoords[3];
678: PetscScalar *coords;
679: PetscInt numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
680: PetscMPIInt rank, size;
681: char **names, **colors, **lcolors;
682: PetscBool plotEdges, flg;
684: DMGetDimension(dm, &dim);
685: DMPlexGetDepth(dm, &depth);
686: DMGetNumLabels(dm, &numLabels);
687: numLabels = PetscMax(numLabels, 10);
688: numColors = 10;
689: numLColors = 10;
690: PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
691: PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
692: PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);
693: PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
694: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
695: if (!useLabels) numLabels = 0;
696: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
697: if (!useColors) {
698: numColors = 3;
699: for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
700: }
701: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
702: if (!useColors) {
703: numLColors = 4;
704: for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
705: }
706: plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
707: PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);
708: if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
709: if (depth < dim) plotEdges = PETSC_FALSE;
710: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
711: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
712: PetscObjectGetName((PetscObject) dm, &name);
713: PetscViewerASCIIPrintf(viewer, "\
714: \\documentclass[tikz]{standalone}\n\n\
715: \\usepackage{pgflibraryshapes}\n\
716: \\usetikzlibrary{backgrounds}\n\
717: \\usetikzlibrary{arrows}\n\
718: \\begin{document}\n");
719: if (size > 1) {
720: PetscViewerASCIIPrintf(viewer, "%s for process ", name);
721: for (p = 0; p < size; ++p) {
722: if (p > 0 && p == size-1) {
723: PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
724: } else if (p > 0) {
725: PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
726: }
727: PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
728: }
729: PetscViewerASCIIPrintf(viewer, ".\n\n\n");
730: }
731: PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", tikzscale);
732: /* Plot vertices */
733: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
734: VecGetArray(coordinates, &coords);
735: PetscViewerASCIIPushSynchronized(viewer);
736: for (v = vStart; v < vEnd; ++v) {
737: PetscInt off, dof, d;
738: PetscBool isLabeled = PETSC_FALSE;
740: PetscSectionGetDof(coordSection, v, &dof);
741: PetscSectionGetOffset(coordSection, v, &off);
742: PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
743: if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
744: for (d = 0; d < dof; ++d) {
745: tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
746: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
747: }
748: /* Rotate coordinates since PGF makes z point out of the page instead of up */
749: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
750: for (d = 0; d < dof; ++d) {
751: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
752: PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
753: }
754: color = colors[rank%numColors];
755: for (l = 0; l < numLabels; ++l) {
756: PetscInt val;
757: DMGetLabelValue(dm, names[l], v, &val);
758: if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
759: }
760: if (useNumbers) {
761: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
762: } else {
763: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
764: }
765: }
766: VecRestoreArray(coordinates, &coords);
767: PetscViewerFlush(viewer);
768: /* Plot cells */
769: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
770: DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
771: if (dim == 3 || !useNumbers) {
772: for (e = eStart; e < eEnd; ++e) {
773: const PetscInt *cone;
775: color = colors[rank%numColors];
776: for (l = 0; l < numLabels; ++l) {
777: PetscInt val;
778: DMGetLabelValue(dm, names[l], e, &val);
779: if (val >= 0) {color = lcolors[l%numLColors]; break;}
780: }
781: DMPlexGetCone(dm, e, &cone);
782: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
783: }
784: } else {
785: for (c = cStart; c < cEnd; ++c) {
786: PetscInt *closure = NULL;
787: PetscInt closureSize, firstPoint = -1;
789: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
790: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
791: for (p = 0; p < closureSize*2; p += 2) {
792: const PetscInt point = closure[p];
794: if ((point < vStart) || (point >= vEnd)) continue;
795: if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
796: PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
797: if (firstPoint < 0) firstPoint = point;
798: }
799: /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
800: PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
801: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
802: }
803: }
804: VecGetArray(coordinates, &coords);
805: for (c = cStart; c < cEnd; ++c) {
806: double ccoords[3] = {0.0, 0.0, 0.0};
807: PetscBool isLabeled = PETSC_FALSE;
808: PetscInt *closure = NULL;
809: PetscInt closureSize, dof, d, n = 0;
811: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
812: PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
813: for (p = 0; p < closureSize*2; p += 2) {
814: const PetscInt point = closure[p];
815: PetscInt off;
817: if ((point < vStart) || (point >= vEnd)) continue;
818: PetscSectionGetDof(coordSection, point, &dof);
819: PetscSectionGetOffset(coordSection, point, &off);
820: for (d = 0; d < dof; ++d) {
821: tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
822: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
823: }
824: /* Rotate coordinates since PGF makes z point out of the page instead of up */
825: if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
826: for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
827: ++n;
828: }
829: for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
830: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
831: for (d = 0; d < dof; ++d) {
832: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
833: PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d]);
834: }
835: color = colors[rank%numColors];
836: for (l = 0; l < numLabels; ++l) {
837: PetscInt val;
838: DMGetLabelValue(dm, names[l], c, &val);
839: if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
840: }
841: if (useNumbers) {
842: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);
843: } else {
844: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);
845: }
846: }
847: VecRestoreArray(coordinates, &coords);
848: /* Plot edges */
849: if (plotEdges) {
850: VecGetArray(coordinates, &coords);
851: PetscViewerASCIIPrintf(viewer, "\\path\n");
852: for (e = eStart; e < eEnd; ++e) {
853: const PetscInt *cone;
854: PetscInt coneSize, offA, offB, dof, d;
856: DMPlexGetConeSize(dm, e, &coneSize);
857: if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
858: DMPlexGetCone(dm, e, &cone);
859: PetscSectionGetDof(coordSection, cone[0], &dof);
860: PetscSectionGetOffset(coordSection, cone[0], &offA);
861: PetscSectionGetOffset(coordSection, cone[1], &offB);
862: PetscViewerASCIISynchronizedPrintf(viewer, "(");
863: for (d = 0; d < dof; ++d) {
864: tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
865: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
866: }
867: /* Rotate coordinates since PGF makes z point out of the page instead of up */
868: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
869: for (d = 0; d < dof; ++d) {
870: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
871: PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
872: }
873: color = colors[rank%numColors];
874: for (l = 0; l < numLabels; ++l) {
875: PetscInt val;
876: DMGetLabelValue(dm, names[l], v, &val);
877: if (val >= 0) {color = lcolors[l%numLColors]; break;}
878: }
879: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
880: }
881: VecRestoreArray(coordinates, &coords);
882: PetscViewerFlush(viewer);
883: PetscViewerASCIIPrintf(viewer, "(0,0);\n");
884: }
885: PetscViewerFlush(viewer);
886: PetscViewerASCIIPopSynchronized(viewer);
887: PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
888: PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
889: for (l = 0; l < numLabels; ++l) {PetscFree(names[l]);}
890: for (c = 0; c < numColors; ++c) {PetscFree(colors[c]);}
891: for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
892: PetscFree3(names, colors, lcolors);
893: } else {
894: MPI_Comm comm;
895: PetscInt *sizes, *hybsizes;
896: PetscInt locDepth, depth, cellHeight, dim, d, pMax[4];
897: PetscInt pStart, pEnd, p;
898: PetscInt numLabels, l;
899: const char *name;
900: PetscMPIInt size;
902: PetscObjectGetComm((PetscObject)dm,&comm);
903: MPI_Comm_size(comm, &size);
904: DMGetDimension(dm, &dim);
905: DMPlexGetVTKCellHeight(dm, &cellHeight);
906: PetscObjectGetName((PetscObject) dm, &name);
907: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
908: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
909: if (cellHeight) {PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);}
910: DMPlexGetDepth(dm, &locDepth);
911: MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
912: DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);
913: PetscCalloc2(size,&sizes,size,&hybsizes);
914: if (depth == 1) {
915: DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
916: pEnd = pEnd - pStart;
917: pMax[0] -= pStart;
918: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
919: MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
920: PetscViewerASCIIPrintf(viewer, " %d-cells:", 0);
921: for (p = 0; p < size; ++p) {
922: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
923: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
924: }
925: PetscViewerASCIIPrintf(viewer, "\n");
926: DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
927: pEnd = pEnd - pStart;
928: pMax[depth] -= pStart;
929: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
930: MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
931: PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);
932: for (p = 0; p < size; ++p) {
933: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
934: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
935: }
936: PetscViewerASCIIPrintf(viewer, "\n");
937: } else {
938: PetscMPIInt rank;
939: MPI_Comm_rank(comm, &rank);
940: for (d = 0; d <= dim; d++) {
941: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
942: pEnd -= pStart;
943: pMax[d] -= pStart;
944: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
945: MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
946: PetscViewerASCIIPrintf(viewer, " %D-cells:", d);
947: for (p = 0; p < size; ++p) {
948: if (!rank) {
949: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
950: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
951: }
952: }
953: PetscViewerASCIIPrintf(viewer, "\n");
954: }
955: }
956: PetscFree2(sizes,hybsizes);
957: DMGetNumLabels(dm, &numLabels);
958: if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
959: for (l = 0; l < numLabels; ++l) {
960: DMLabel label;
961: const char *name;
962: IS valueIS;
963: const PetscInt *values;
964: PetscInt numValues, v;
966: DMGetLabelName(dm, l, &name);
967: DMGetLabel(dm, name, &label);
968: DMLabelGetNumValues(label, &numValues);
969: PetscViewerASCIIPrintf(viewer, " %s: %D strata with value/size (", name, numValues);
970: DMLabelGetValueIS(label, &valueIS);
971: ISGetIndices(valueIS, &values);
972: PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
973: for (v = 0; v < numValues; ++v) {
974: PetscInt size;
976: DMLabelGetStratumSize(label, values[v], &size);
977: if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
978: PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
979: }
980: PetscViewerASCIIPrintf(viewer, ")\n");
981: PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
982: ISRestoreIndices(valueIS, &values);
983: ISDestroy(&valueIS);
984: }
985: /* If no fields are specified, people do not want to see adjacency */
986: if (dm->Nf) {
987: PetscInt f;
989: for (f = 0; f < dm->Nf; ++f) {
990: const char *name;
992: PetscObjectGetName(dm->fields[f].disc, &name);
993: if (numLabels) {PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);}
994: PetscViewerASCIIPushTab(viewer);
995: if (dm->fields[f].label) {DMLabelView(dm->fields[f].label, viewer);}
996: if (dm->fields[f].adjacency[0]) {
997: if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");}
998: else {PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");}
999: } else {
1000: if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");}
1001: else {PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");}
1002: }
1003: PetscViewerASCIIPopTab(viewer);
1004: }
1005: }
1006: DMGetCoarseDM(dm, &cdm);
1007: if (cdm) {
1008: PetscViewerASCIIPushTab(viewer);
1009: DMPlexView_Ascii(cdm, viewer);
1010: PetscViewerASCIIPopTab(viewer);
1011: }
1012: }
1013: return(0);
1014: }
1016: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1017: {
1018: PetscDraw draw;
1019: DM cdm;
1020: PetscSection coordSection;
1021: Vec coordinates;
1022: const PetscScalar *coords;
1023: PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1024: PetscBool isnull;
1025: PetscInt dim, vStart, vEnd, cStart, cEnd, c, N;
1026: PetscMPIInt rank;
1027: PetscErrorCode ierr;
1030: DMGetCoordinateDim(dm, &dim);
1031: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1032: DMGetCoordinateDM(dm, &cdm);
1033: DMGetSection(cdm, &coordSection);
1034: DMGetCoordinatesLocal(dm, &coordinates);
1035: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1036: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1038: PetscViewerDrawGetDraw(viewer, 0, &draw);
1039: PetscDrawIsNull(draw, &isnull);
1040: if (isnull) return(0);
1041: PetscDrawSetTitle(draw, "Mesh");
1043: VecGetLocalSize(coordinates, &N);
1044: VecGetArrayRead(coordinates, &coords);
1045: for (c = 0; c < N; c += dim) {
1046: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1047: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1048: }
1049: VecRestoreArrayRead(coordinates, &coords);
1050: MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1051: MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1052: PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1053: PetscDrawClear(draw);
1055: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1056: for (c = cStart; c < cEnd; ++c) {
1057: PetscScalar *coords = NULL;
1058: PetscInt numCoords,coneSize;
1060: DMPlexGetConeSize(dm, c, &coneSize);
1061: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1062: switch (coneSize) {
1063: case 3:
1064: PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1065: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1066: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1067: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1068: break;
1069: case 4:
1070: PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1071: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1072: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1073: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1074: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1075: break;
1076: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1077: }
1078: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1079: }
1080: for (c = cStart; c < cEnd; ++c) {
1081: PetscScalar *coords = NULL;
1082: PetscInt numCoords,coneSize;
1084: DMPlexGetConeSize(dm, c, &coneSize);
1085: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1086: switch (coneSize) {
1087: case 3:
1088: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1089: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1090: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1091: break;
1092: case 4:
1093: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1094: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1095: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
1096: PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1097: break;
1098: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1099: }
1100: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1101: }
1102: PetscDrawFlush(draw);
1103: PetscDrawPause(draw);
1104: PetscDrawSave(draw);
1105: return(0);
1106: }
1108: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1109: {
1110: PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1111: char name[PETSC_MAX_PATH_LEN];
1117: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
1118: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
1119: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
1120: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
1121: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
1122: if (iascii) {
1123: PetscViewerFormat format;
1124: PetscViewerGetFormat(viewer, &format);
1125: if (format == PETSC_VIEWER_ASCII_GLVIS) {
1126: DMPlexView_GLVis(dm, viewer);
1127: } else {
1128: DMPlexView_Ascii(dm, viewer);
1129: }
1130: } else if (ishdf5) {
1131: #if defined(PETSC_HAVE_HDF5)
1132: DMPlexView_HDF5_Internal(dm, viewer);
1133: #else
1134: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1135: #endif
1136: } else if (isvtk) {
1137: DMPlexVTKWriteAll((PetscObject) dm,viewer);
1138: } else if (isdraw) {
1139: DMPlexView_Draw(dm, viewer);
1140: } else if (isglvis) {
1141: DMPlexView_GLVis(dm, viewer);
1142: } else {
1143: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1144: }
1145: /* Optionally view the partition */
1146: PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1147: if (flg) {
1148: Vec ranks;
1149: DMPlexCreateRankField(dm, &ranks);
1150: VecView(ranks, viewer);
1151: VecDestroy(&ranks);
1152: }
1153: /* Optionally view a label */
1154: PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, PETSC_MAX_PATH_LEN, &flg);
1155: if (flg) {
1156: DMLabel label;
1157: Vec val;
1159: DMGetLabel(dm, name, &label);
1160: if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1161: DMPlexCreateLabelField(dm, label, &val);
1162: VecView(val, viewer);
1163: VecDestroy(&val);
1164: }
1165: return(0);
1166: }
1168: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1169: {
1170: PetscBool ishdf5;
1176: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
1177: if (ishdf5) {
1178: #if defined(PETSC_HAVE_HDF5)
1179: PetscViewerFormat format;
1180: PetscViewerGetFormat(viewer, &format);
1181: if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1182: DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1183: } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1184: DMPlexLoad_HDF5_Internal(dm, viewer);
1185: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1186: #else
1187: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1188: #endif
1189: } else {
1190: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1191: }
1192: return(0);
1193: }
1195: PetscErrorCode DMDestroy_Plex(DM dm)
1196: {
1197: DM_Plex *mesh = (DM_Plex*) dm->data;
1201: PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1202: PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1203: if (--mesh->refct > 0) return(0);
1204: PetscSectionDestroy(&mesh->coneSection);
1205: PetscFree(mesh->cones);
1206: PetscFree(mesh->coneOrientations);
1207: PetscSectionDestroy(&mesh->supportSection);
1208: PetscSectionDestroy(&mesh->subdomainSection);
1209: PetscFree(mesh->supports);
1210: PetscFree(mesh->facesTmp);
1211: PetscFree(mesh->tetgenOpts);
1212: PetscFree(mesh->triangleOpts);
1213: PetscPartitionerDestroy(&mesh->partitioner);
1214: DMLabelDestroy(&mesh->subpointMap);
1215: ISDestroy(&mesh->globalVertexNumbers);
1216: ISDestroy(&mesh->globalCellNumbers);
1217: PetscSectionDestroy(&mesh->anchorSection);
1218: ISDestroy(&mesh->anchorIS);
1219: PetscSectionDestroy(&mesh->parentSection);
1220: PetscFree(mesh->parents);
1221: PetscFree(mesh->childIDs);
1222: PetscSectionDestroy(&mesh->childSection);
1223: PetscFree(mesh->children);
1224: DMDestroy(&mesh->referenceTree);
1225: PetscGridHashDestroy(&mesh->lbox);
1226: /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1227: PetscFree(mesh);
1228: return(0);
1229: }
1231: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1232: {
1233: PetscSection sectionGlobal;
1234: PetscInt bs = -1, mbs;
1235: PetscInt localSize;
1236: PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1237: PetscErrorCode ierr;
1238: MatType mtype;
1239: ISLocalToGlobalMapping ltog;
1242: MatInitializePackage();
1243: mtype = dm->mattype;
1244: DMGetGlobalSection(dm, §ionGlobal);
1245: /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1246: PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1247: MatCreate(PetscObjectComm((PetscObject)dm), J);
1248: MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1249: MatSetType(*J, mtype);
1250: MatSetFromOptions(*J);
1251: MatGetBlockSize(*J, &mbs);
1252: if (mbs > 1) bs = mbs;
1253: PetscStrcmp(mtype, MATSHELL, &isShell);
1254: PetscStrcmp(mtype, MATBAIJ, &isBlock);
1255: PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1256: PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1257: PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1258: PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1259: PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1260: PetscStrcmp(mtype, MATIS, &isMatIS);
1261: if (!isShell) {
1262: PetscSection subSection;
1263: PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1264: PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1265: PetscInt pStart, pEnd, p, dof, cdof;
1267: /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
1268: if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
1269: PetscSection section;
1270: PetscInt size;
1272: DMGetSection(dm, §ion);
1273: PetscSectionGetStorageSize(section, &size);
1274: PetscMalloc1(size,<ogidx);
1275: DMPlexGetSubdomainSection(dm, &subSection);
1276: } else {
1277: DMGetLocalToGlobalMapping(dm,<og);
1278: }
1279: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1280: for (p = pStart, lsize = 0; p < pEnd; ++p) {
1281: PetscInt bdof;
1283: PetscSectionGetDof(sectionGlobal, p, &dof);
1284: PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1285: dof = dof < 0 ? -(dof+1) : dof;
1286: bdof = cdof && (dof-cdof) ? 1 : dof;
1287: if (dof) {
1288: if (bs < 0) {bs = bdof;}
1289: else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1290: }
1291: if (isMatIS) {
1292: PetscInt loff,c,off;
1293: PetscSectionGetOffset(subSection, p, &loff);
1294: PetscSectionGetOffset(sectionGlobal, p, &off);
1295: for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1296: }
1297: }
1298: /* Must have same blocksize on all procs (some might have no points) */
1299: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1300: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1301: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1302: else {bs = bsMinMax[0];}
1303: bs = bs < 0 ? 1 : bs;
1304: if (isMatIS) {
1305: PetscInt l;
1306: /* Must reduce indices by blocksize */
1307: if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1308: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, <og);
1309: }
1310: MatSetLocalToGlobalMapping(*J,ltog,ltog);
1311: if (isMatIS) {
1312: ISLocalToGlobalMappingDestroy(<og);
1313: }
1314: PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1315: DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1316: PetscFree4(dnz, onz, dnzu, onzu);
1317: }
1318: MatSetDM(*J, dm);
1319: return(0);
1320: }
1322: /*@
1323: DMPlexGetSubdomainSection - Returns the section associated with the subdomain
1325: Not collective
1327: Input Parameter:
1328: . mesh - The DMPlex
1330: Output Parameters:
1331: . subsection - The subdomain section
1333: Level: developer
1335: .seealso:
1336: @*/
1337: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1338: {
1339: DM_Plex *mesh = (DM_Plex*) dm->data;
1344: if (!mesh->subdomainSection) {
1345: PetscSection section;
1346: PetscSF sf;
1348: PetscSFCreate(PETSC_COMM_SELF,&sf);
1349: DMGetSection(dm,§ion);
1350: PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1351: PetscSFDestroy(&sf);
1352: }
1353: *subsection = mesh->subdomainSection;
1354: return(0);
1355: }
1357: /*@
1358: DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1360: Not collective
1362: Input Parameter:
1363: . mesh - The DMPlex
1365: Output Parameters:
1366: + pStart - The first mesh point
1367: - pEnd - The upper bound for mesh points
1369: Level: beginner
1371: .seealso: DMPlexCreate(), DMPlexSetChart()
1372: @*/
1373: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1374: {
1375: DM_Plex *mesh = (DM_Plex*) dm->data;
1380: PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1381: return(0);
1382: }
1384: /*@
1385: DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1387: Not collective
1389: Input Parameters:
1390: + mesh - The DMPlex
1391: . pStart - The first mesh point
1392: - pEnd - The upper bound for mesh points
1394: Output Parameters:
1396: Level: beginner
1398: .seealso: DMPlexCreate(), DMPlexGetChart()
1399: @*/
1400: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1401: {
1402: DM_Plex *mesh = (DM_Plex*) dm->data;
1407: PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1408: PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1409: return(0);
1410: }
1412: /*@
1413: DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
1415: Not collective
1417: Input Parameters:
1418: + mesh - The DMPlex
1419: - p - The point, which must lie in the chart set with DMPlexSetChart()
1421: Output Parameter:
1422: . size - The cone size for point p
1424: Level: beginner
1426: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1427: @*/
1428: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1429: {
1430: DM_Plex *mesh = (DM_Plex*) dm->data;
1436: PetscSectionGetDof(mesh->coneSection, p, size);
1437: return(0);
1438: }
1440: /*@
1441: DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
1443: Not collective
1445: Input Parameters:
1446: + mesh - The DMPlex
1447: . p - The point, which must lie in the chart set with DMPlexSetChart()
1448: - size - The cone size for point p
1450: Output Parameter:
1452: Note:
1453: This should be called after DMPlexSetChart().
1455: Level: beginner
1457: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1458: @*/
1459: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1460: {
1461: DM_Plex *mesh = (DM_Plex*) dm->data;
1466: PetscSectionSetDof(mesh->coneSection, p, size);
1468: mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1469: return(0);
1470: }
1472: /*@
1473: DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
1475: Not collective
1477: Input Parameters:
1478: + mesh - The DMPlex
1479: . p - The point, which must lie in the chart set with DMPlexSetChart()
1480: - size - The additional cone size for point p
1482: Output Parameter:
1484: Note:
1485: This should be called after DMPlexSetChart().
1487: Level: beginner
1489: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1490: @*/
1491: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1492: {
1493: DM_Plex *mesh = (DM_Plex*) dm->data;
1494: PetscInt csize;
1499: PetscSectionAddDof(mesh->coneSection, p, size);
1500: PetscSectionGetDof(mesh->coneSection, p, &csize);
1502: mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1503: return(0);
1504: }
1506: /*@C
1507: DMPlexGetCone - Return the points on the in-edges for this point in the DAG
1509: Not collective
1511: Input Parameters:
1512: + dm - The DMPlex
1513: - p - The point, which must lie in the chart set with DMPlexSetChart()
1515: Output Parameter:
1516: . cone - An array of points which are on the in-edges for point p
1518: Level: beginner
1520: Fortran Notes:
1521: Since it returns an array, this routine is only available in Fortran 90, and you must
1522: include petsc.h90 in your code.
1524: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1525: @*/
1526: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1527: {
1528: DM_Plex *mesh = (DM_Plex*) dm->data;
1529: PetscInt off;
1535: PetscSectionGetOffset(mesh->coneSection, p, &off);
1536: *cone = &mesh->cones[off];
1537: return(0);
1538: }
1540: /*@C
1541: DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
1543: Not collective
1545: Input Parameters:
1546: + dm - The DMPlex
1547: - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
1549: Output Parameter:
1550: + pConesSection - PetscSection describing the layout of pCones
1551: - pCones - An array of points which are on the in-edges for the point set p
1553: Level: intermediate
1555: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1556: @*/
1557: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1558: {
1559: PetscSection cs, newcs;
1560: PetscInt *cones;
1561: PetscInt *newarr=NULL;
1562: PetscInt n;
1563: PetscErrorCode ierr;
1566: DMPlexGetCones(dm, &cones);
1567: DMPlexGetConeSection(dm, &cs);
1568: PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1569: if (pConesSection) *pConesSection = newcs;
1570: if (pCones) {
1571: PetscSectionGetStorageSize(newcs, &n);
1572: ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1573: }
1574: return(0);
1575: }
1577: static PetscErrorCode DMPlexGetConeRecursive_Private(DM dm, PetscInt *n_inout, const PetscInt points[], PetscInt *offset_inout, PetscInt buf[])
1578: {
1579: PetscInt p, n, cn, i;
1580: const PetscInt *cone;
1584: n = *n_inout;
1585: *n_inout = 0;
1586: for (i=0; i<n; i++) {
1587: p = points[i];
1588: DMPlexGetConeSize(dm, p, &cn);
1589: if (!cn) {
1590: cn = 1;
1591: if (buf) {
1592: buf[*offset_inout] = p;
1593: ++(*offset_inout);
1594: }
1595: } else {
1596: DMPlexGetCone(dm, p, &cone);
1597: DMPlexGetConeRecursive_Private(dm, &cn, cone, offset_inout, buf);
1598: }
1599: *n_inout += cn;
1600: }
1601: return(0);
1602: }
1604: /*@C
1605: DMPlexGetConeRecursive - Like DMPlexGetConeTuple() but recursive, i.e. each cone point is expanded into a set of its own cone points until a vertex (DAG point with no cone) is reached.
1607: Not collective
1609: Input Parameters:
1610: + dm - The DMPlex
1611: - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
1613: Output Parameter:
1614: . pCones - An array of recursively expanded cones, i.e. containing only vertices, and each of them can be present multiple times
1616: Level: advanced
1618: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple()
1619: @*/
1620: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS p, IS *pCones)
1621: {
1622: const PetscInt *arr=NULL;
1623: PetscInt *cpoints=NULL;
1624: PetscInt n, cn;
1625: PetscInt zero;
1626: PetscErrorCode ierr;
1629: ISGetLocalSize(p, &n);
1630: ISGetIndices(p, &arr);
1631: zero = 0;
1632: /* first figure out the total number of returned points */
1633: cn = n;
1634: DMPlexGetConeRecursive_Private(dm, &cn, arr, &zero, NULL);
1635: PetscMalloc1(cn, &cpoints);
1636: /* now get recursive cones themselves */
1637: DMPlexGetConeRecursive_Private(dm, &n, arr, &zero, cpoints);
1638: ISCreateGeneral(PetscObjectComm((PetscObject)p), n, cpoints, PETSC_OWN_POINTER, pCones);
1639: ISRestoreIndices(p, &arr);
1640: return(0);
1641: }
1643: /*@
1644: DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point
1646: Not collective
1648: Input Parameters:
1649: + mesh - The DMPlex
1650: . p - The point, which must lie in the chart set with DMPlexSetChart()
1651: - cone - An array of points which are on the in-edges for point p
1653: Output Parameter:
1655: Note:
1656: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1658: Developer Note: Why not call this DMPlexSetCover()
1660: Level: beginner
1662: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1663: @*/
1664: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1665: {
1666: DM_Plex *mesh = (DM_Plex*) dm->data;
1667: PetscInt pStart, pEnd;
1668: PetscInt dof, off, c;
1673: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1674: PetscSectionGetDof(mesh->coneSection, p, &dof);
1676: PetscSectionGetOffset(mesh->coneSection, p, &off);
1677: 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);
1678: for (c = 0; c < dof; ++c) {
1679: 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);
1680: mesh->cones[off+c] = cone[c];
1681: }
1682: return(0);
1683: }
1685: /*@C
1686: DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
1688: Not collective
1690: Input Parameters:
1691: + mesh - The DMPlex
1692: - p - The point, which must lie in the chart set with DMPlexSetChart()
1694: Output Parameter:
1695: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1696: integer giving the prescription for cone traversal. If it is negative, the cone is
1697: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1698: the index of the cone point on which to start.
1700: Level: beginner
1702: Fortran Notes:
1703: Since it returns an array, this routine is only available in Fortran 90, and you must
1704: include petsc.h90 in your code.
1706: You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1708: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1709: @*/
1710: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1711: {
1712: DM_Plex *mesh = (DM_Plex*) dm->data;
1713: PetscInt off;
1718: #if defined(PETSC_USE_DEBUG)
1719: {
1720: PetscInt dof;
1721: PetscSectionGetDof(mesh->coneSection, p, &dof);
1723: }
1724: #endif
1725: PetscSectionGetOffset(mesh->coneSection, p, &off);
1727: *coneOrientation = &mesh->coneOrientations[off];
1728: return(0);
1729: }
1731: /*@
1732: DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
1734: Not collective
1736: Input Parameters:
1737: + mesh - The DMPlex
1738: . p - The point, which must lie in the chart set with DMPlexSetChart()
1739: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1740: integer giving the prescription for cone traversal. If it is negative, the cone is
1741: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1742: the index of the cone point on which to start.
1744: Output Parameter:
1746: Note:
1747: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1749: Level: beginner
1751: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1752: @*/
1753: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1754: {
1755: DM_Plex *mesh = (DM_Plex*) dm->data;
1756: PetscInt pStart, pEnd;
1757: PetscInt dof, off, c;
1762: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1763: PetscSectionGetDof(mesh->coneSection, p, &dof);
1765: PetscSectionGetOffset(mesh->coneSection, p, &off);
1766: 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);
1767: for (c = 0; c < dof; ++c) {
1768: PetscInt cdof, o = coneOrientation[c];
1770: PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1771: 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);
1772: mesh->coneOrientations[off+c] = o;
1773: }
1774: return(0);
1775: }
1777: /*@
1778: DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
1780: Not collective
1782: Input Parameters:
1783: + mesh - The DMPlex
1784: . p - The point, which must lie in the chart set with DMPlexSetChart()
1785: . conePos - The local index in the cone where the point should be put
1786: - conePoint - The mesh point to insert
1788: Level: beginner
1790: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1791: @*/
1792: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1793: {
1794: DM_Plex *mesh = (DM_Plex*) dm->data;
1795: PetscInt pStart, pEnd;
1796: PetscInt dof, off;
1801: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1802: 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);
1803: 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);
1804: PetscSectionGetDof(mesh->coneSection, p, &dof);
1805: PetscSectionGetOffset(mesh->coneSection, p, &off);
1806: 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);
1807: mesh->cones[off+conePos] = conePoint;
1808: return(0);
1809: }
1811: /*@
1812: DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
1814: Not collective
1816: Input Parameters:
1817: + mesh - The DMPlex
1818: . p - The point, which must lie in the chart set with DMPlexSetChart()
1819: . conePos - The local index in the cone where the point should be put
1820: - coneOrientation - The point orientation to insert
1822: Level: beginner
1824: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1825: @*/
1826: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1827: {
1828: DM_Plex *mesh = (DM_Plex*) dm->data;
1829: PetscInt pStart, pEnd;
1830: PetscInt dof, off;
1835: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1836: 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);
1837: PetscSectionGetDof(mesh->coneSection, p, &dof);
1838: PetscSectionGetOffset(mesh->coneSection, p, &off);
1839: 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);
1840: mesh->coneOrientations[off+conePos] = coneOrientation;
1841: return(0);
1842: }
1844: /*@
1845: DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
1847: Not collective
1849: Input Parameters:
1850: + mesh - The DMPlex
1851: - p - The point, which must lie in the chart set with DMPlexSetChart()
1853: Output Parameter:
1854: . size - The support size for point p
1856: Level: beginner
1858: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1859: @*/
1860: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1861: {
1862: DM_Plex *mesh = (DM_Plex*) dm->data;
1868: PetscSectionGetDof(mesh->supportSection, p, size);
1869: return(0);
1870: }
1872: /*@
1873: DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
1875: Not collective
1877: Input Parameters:
1878: + mesh - The DMPlex
1879: . p - The point, which must lie in the chart set with DMPlexSetChart()
1880: - size - The support size for point p
1882: Output Parameter:
1884: Note:
1885: This should be called after DMPlexSetChart().
1887: Level: beginner
1889: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1890: @*/
1891: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1892: {
1893: DM_Plex *mesh = (DM_Plex*) dm->data;
1898: PetscSectionSetDof(mesh->supportSection, p, size);
1900: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1901: return(0);
1902: }
1904: /*@C
1905: DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
1907: Not collective
1909: Input Parameters:
1910: + mesh - The DMPlex
1911: - p - The point, which must lie in the chart set with DMPlexSetChart()
1913: Output Parameter:
1914: . support - An array of points which are on the out-edges for point p
1916: Level: beginner
1918: Fortran Notes:
1919: Since it returns an array, this routine is only available in Fortran 90, and you must
1920: include petsc.h90 in your code.
1922: You must also call DMPlexRestoreSupport() after you finish using the returned array.
1924: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1925: @*/
1926: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1927: {
1928: DM_Plex *mesh = (DM_Plex*) dm->data;
1929: PetscInt off;
1935: PetscSectionGetOffset(mesh->supportSection, p, &off);
1936: *support = &mesh->supports[off];
1937: return(0);
1938: }
1940: /*@
1941: DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
1943: Not collective
1945: Input Parameters:
1946: + mesh - The DMPlex
1947: . p - The point, which must lie in the chart set with DMPlexSetChart()
1948: - support - An array of points which are on the out-edges for point p
1950: Output Parameter:
1952: Note:
1953: This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1955: Level: beginner
1957: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1958: @*/
1959: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1960: {
1961: DM_Plex *mesh = (DM_Plex*) dm->data;
1962: PetscInt pStart, pEnd;
1963: PetscInt dof, off, c;
1968: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1969: PetscSectionGetDof(mesh->supportSection, p, &dof);
1971: PetscSectionGetOffset(mesh->supportSection, p, &off);
1972: 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);
1973: for (c = 0; c < dof; ++c) {
1974: 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);
1975: mesh->supports[off+c] = support[c];
1976: }
1977: return(0);
1978: }
1980: /*@
1981: DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
1983: Not collective
1985: Input Parameters:
1986: + mesh - The DMPlex
1987: . p - The point, which must lie in the chart set with DMPlexSetChart()
1988: . supportPos - The local index in the cone where the point should be put
1989: - supportPoint - The mesh point to insert
1991: Level: beginner
1993: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1994: @*/
1995: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1996: {
1997: DM_Plex *mesh = (DM_Plex*) dm->data;
1998: PetscInt pStart, pEnd;
1999: PetscInt dof, off;
2004: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2005: PetscSectionGetDof(mesh->supportSection, p, &dof);
2006: PetscSectionGetOffset(mesh->supportSection, p, &off);
2007: 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);
2008: 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);
2009: 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);
2010: mesh->supports[off+supportPos] = supportPoint;
2011: return(0);
2012: }
2014: /*@C
2015: DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
2017: Not collective
2019: Input Parameters:
2020: + mesh - The DMPlex
2021: . p - The point, which must lie in the chart set with DMPlexSetChart()
2022: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2023: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2025: Output Parameters:
2026: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2027: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2029: Note:
2030: If using internal storage (points is NULL on input), each call overwrites the last output.
2032: Fortran Notes:
2033: Since it returns an array, this routine is only available in Fortran 90, and you must
2034: include petsc.h90 in your code.
2036: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2038: Level: beginner
2040: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2041: @*/
2042: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2043: {
2044: DM_Plex *mesh = (DM_Plex*) dm->data;
2045: PetscInt *closure, *fifo;
2046: const PetscInt *tmp = NULL, *tmpO = NULL;
2047: PetscInt tmpSize, t;
2048: PetscInt depth = 0, maxSize;
2049: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
2050: PetscErrorCode ierr;
2054: DMPlexGetDepth(dm, &depth);
2055: /* This is only 1-level */
2056: if (useCone) {
2057: DMPlexGetConeSize(dm, p, &tmpSize);
2058: DMPlexGetCone(dm, p, &tmp);
2059: DMPlexGetConeOrientation(dm, p, &tmpO);
2060: } else {
2061: DMPlexGetSupportSize(dm, p, &tmpSize);
2062: DMPlexGetSupport(dm, p, &tmp);
2063: }
2064: if (depth == 1) {
2065: if (*points) {
2066: closure = *points;
2067: } else {
2068: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2069: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2070: }
2071: closure[0] = p; closure[1] = 0;
2072: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2073: closure[closureSize] = tmp[t];
2074: closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2075: }
2076: if (numPoints) *numPoints = closureSize/2;
2077: if (points) *points = closure;
2078: return(0);
2079: }
2080: {
2081: PetscInt c, coneSeries, s,supportSeries;
2083: c = mesh->maxConeSize;
2084: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2085: s = mesh->maxSupportSize;
2086: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2087: maxSize = 2*PetscMax(coneSeries,supportSeries);
2088: }
2089: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2090: if (*points) {
2091: closure = *points;
2092: } else {
2093: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2094: }
2095: closure[0] = p; closure[1] = 0;
2096: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2097: const PetscInt cp = tmp[t];
2098: const PetscInt co = tmpO ? tmpO[t] : 0;
2100: closure[closureSize] = cp;
2101: closure[closureSize+1] = co;
2102: fifo[fifoSize] = cp;
2103: fifo[fifoSize+1] = co;
2104: }
2105: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2106: while (fifoSize - fifoStart) {
2107: const PetscInt q = fifo[fifoStart];
2108: const PetscInt o = fifo[fifoStart+1];
2109: const PetscInt rev = o >= 0 ? 0 : 1;
2110: const PetscInt off = rev ? -(o+1) : o;
2112: if (useCone) {
2113: DMPlexGetConeSize(dm, q, &tmpSize);
2114: DMPlexGetCone(dm, q, &tmp);
2115: DMPlexGetConeOrientation(dm, q, &tmpO);
2116: } else {
2117: DMPlexGetSupportSize(dm, q, &tmpSize);
2118: DMPlexGetSupport(dm, q, &tmp);
2119: tmpO = NULL;
2120: }
2121: for (t = 0; t < tmpSize; ++t) {
2122: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
2123: const PetscInt cp = tmp[i];
2124: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2125: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2126: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2127: PetscInt co = tmpO ? tmpO[i] : 0;
2128: PetscInt c;
2130: if (rev) {
2131: PetscInt childSize, coff;
2132: DMPlexGetConeSize(dm, cp, &childSize);
2133: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2134: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2135: }
2136: /* Check for duplicate */
2137: for (c = 0; c < closureSize; c += 2) {
2138: if (closure[c] == cp) break;
2139: }
2140: if (c == closureSize) {
2141: closure[closureSize] = cp;
2142: closure[closureSize+1] = co;
2143: fifo[fifoSize] = cp;
2144: fifo[fifoSize+1] = co;
2145: closureSize += 2;
2146: fifoSize += 2;
2147: }
2148: }
2149: fifoStart += 2;
2150: }
2151: if (numPoints) *numPoints = closureSize/2;
2152: if (points) *points = closure;
2153: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2154: return(0);
2155: }
2157: /*@C
2158: DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG with a specified initial orientation
2160: Not collective
2162: Input Parameters:
2163: + mesh - The DMPlex
2164: . p - The point, which must lie in the chart set with DMPlexSetChart()
2165: . orientation - The orientation of the point
2166: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2167: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2169: Output Parameters:
2170: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2171: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2173: Note:
2174: If using internal storage (points is NULL on input), each call overwrites the last output.
2176: Fortran Notes:
2177: Since it returns an array, this routine is only available in Fortran 90, and you must
2178: include petsc.h90 in your code.
2180: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2182: Level: beginner
2184: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2185: @*/
2186: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2187: {
2188: DM_Plex *mesh = (DM_Plex*) dm->data;
2189: PetscInt *closure, *fifo;
2190: const PetscInt *tmp = NULL, *tmpO = NULL;
2191: PetscInt tmpSize, t;
2192: PetscInt depth = 0, maxSize;
2193: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
2194: PetscErrorCode ierr;
2198: DMPlexGetDepth(dm, &depth);
2199: /* This is only 1-level */
2200: if (useCone) {
2201: DMPlexGetConeSize(dm, p, &tmpSize);
2202: DMPlexGetCone(dm, p, &tmp);
2203: DMPlexGetConeOrientation(dm, p, &tmpO);
2204: } else {
2205: DMPlexGetSupportSize(dm, p, &tmpSize);
2206: DMPlexGetSupport(dm, p, &tmp);
2207: }
2208: if (depth == 1) {
2209: if (*points) {
2210: closure = *points;
2211: } else {
2212: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2213: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2214: }
2215: closure[0] = p; closure[1] = ornt;
2216: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2217: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2218: closure[closureSize] = tmp[i];
2219: closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2220: }
2221: if (numPoints) *numPoints = closureSize/2;
2222: if (points) *points = closure;
2223: return(0);
2224: }
2225: {
2226: PetscInt c, coneSeries, s,supportSeries;
2228: c = mesh->maxConeSize;
2229: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2230: s = mesh->maxSupportSize;
2231: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2232: maxSize = 2*PetscMax(coneSeries,supportSeries);
2233: }
2234: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2235: if (*points) {
2236: closure = *points;
2237: } else {
2238: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2239: }
2240: closure[0] = p; closure[1] = ornt;
2241: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2242: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2243: const PetscInt cp = tmp[i];
2244: PetscInt co = tmpO ? tmpO[i] : 0;
2246: if (ornt < 0) {
2247: PetscInt childSize, coff;
2248: DMPlexGetConeSize(dm, cp, &childSize);
2249: coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2250: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2251: }
2252: closure[closureSize] = cp;
2253: closure[closureSize+1] = co;
2254: fifo[fifoSize] = cp;
2255: fifo[fifoSize+1] = co;
2256: }
2257: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2258: while (fifoSize - fifoStart) {
2259: const PetscInt q = fifo[fifoStart];
2260: const PetscInt o = fifo[fifoStart+1];
2261: const PetscInt rev = o >= 0 ? 0 : 1;
2262: const PetscInt off = rev ? -(o+1) : o;
2264: if (useCone) {
2265: DMPlexGetConeSize(dm, q, &tmpSize);
2266: DMPlexGetCone(dm, q, &tmp);
2267: DMPlexGetConeOrientation(dm, q, &tmpO);
2268: } else {
2269: DMPlexGetSupportSize(dm, q, &tmpSize);
2270: DMPlexGetSupport(dm, q, &tmp);
2271: tmpO = NULL;
2272: }
2273: for (t = 0; t < tmpSize; ++t) {
2274: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
2275: const PetscInt cp = tmp[i];
2276: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2277: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2278: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2279: PetscInt co = tmpO ? tmpO[i] : 0;
2280: PetscInt c;
2282: if (rev) {
2283: PetscInt childSize, coff;
2284: DMPlexGetConeSize(dm, cp, &childSize);
2285: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2286: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2287: }
2288: /* Check for duplicate */
2289: for (c = 0; c < closureSize; c += 2) {
2290: if (closure[c] == cp) break;
2291: }
2292: if (c == closureSize) {
2293: closure[closureSize] = cp;
2294: closure[closureSize+1] = co;
2295: fifo[fifoSize] = cp;
2296: fifo[fifoSize+1] = co;
2297: closureSize += 2;
2298: fifoSize += 2;
2299: }
2300: }
2301: fifoStart += 2;
2302: }
2303: if (numPoints) *numPoints = closureSize/2;
2304: if (points) *points = closure;
2305: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2306: return(0);
2307: }
2309: /*@C
2310: DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
2312: Not collective
2314: Input Parameters:
2315: + mesh - The DMPlex
2316: . p - The point, which must lie in the chart set with DMPlexSetChart()
2317: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2318: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
2319: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
2321: Note:
2322: If not using internal storage (points is not NULL on input), this call is unnecessary
2324: Fortran Notes:
2325: Since it returns an array, this routine is only available in Fortran 90, and you must
2326: include petsc.h90 in your code.
2328: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2330: Level: beginner
2332: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2333: @*/
2334: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2335: {
2342: DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2343: if (numPoints) *numPoints = 0;
2344: return(0);
2345: }
2347: /*@
2348: DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
2350: Not collective
2352: Input Parameter:
2353: . mesh - The DMPlex
2355: Output Parameters:
2356: + maxConeSize - The maximum number of in-edges
2357: - maxSupportSize - The maximum number of out-edges
2359: Level: beginner
2361: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2362: @*/
2363: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2364: {
2365: DM_Plex *mesh = (DM_Plex*) dm->data;
2369: if (maxConeSize) *maxConeSize = mesh->maxConeSize;
2370: if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2371: return(0);
2372: }
2374: PetscErrorCode DMSetUp_Plex(DM dm)
2375: {
2376: DM_Plex *mesh = (DM_Plex*) dm->data;
2377: PetscInt size;
2382: PetscSectionSetUp(mesh->coneSection);
2383: PetscSectionGetStorageSize(mesh->coneSection, &size);
2384: PetscMalloc1(size, &mesh->cones);
2385: PetscCalloc1(size, &mesh->coneOrientations);
2386: if (mesh->maxSupportSize) {
2387: PetscSectionSetUp(mesh->supportSection);
2388: PetscSectionGetStorageSize(mesh->supportSection, &size);
2389: PetscMalloc1(size, &mesh->supports);
2390: }
2391: return(0);
2392: }
2394: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2395: {
2399: if (subdm) {DMClone(dm, subdm);}
2400: DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2401: if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2402: if (dm->useNatural && dm->sfMigration) {
2403: PetscSF sfMigrationInv,sfNatural;
2404: PetscSection section, sectionSeq;
2406: (*subdm)->sfMigration = dm->sfMigration;
2407: PetscObjectReference((PetscObject) dm->sfMigration);
2408: DMGetSection((*subdm), §ion);
2409: PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2410: PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq);
2411: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2413: DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2414: (*subdm)->sfNatural = sfNatural;
2415: PetscSectionDestroy(§ionSeq);
2416: PetscSFDestroy(&sfMigrationInv);
2417: }
2418: return(0);
2419: }
2421: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2422: {
2424: PetscInt i = 0;
2427: DMClone(dms[0], superdm);
2428: DMCreateSectionSuperDM(dms, len, is, superdm);
2429: (*superdm)->useNatural = PETSC_FALSE;
2430: for (i = 0; i < len; i++){
2431: if (dms[i]->useNatural && dms[i]->sfMigration) {
2432: PetscSF sfMigrationInv,sfNatural;
2433: PetscSection section, sectionSeq;
2435: (*superdm)->sfMigration = dms[i]->sfMigration;
2436: PetscObjectReference((PetscObject) dms[i]->sfMigration);
2437: (*superdm)->useNatural = PETSC_TRUE;
2438: DMGetSection((*superdm), §ion);
2439: PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2440: PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq);
2441: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2443: DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2444: (*superdm)->sfNatural = sfNatural;
2445: PetscSectionDestroy(§ionSeq);
2446: PetscSFDestroy(&sfMigrationInv);
2447: break;
2448: }
2449: }
2450: return(0);
2451: }
2453: /*@
2454: DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
2456: Not collective
2458: Input Parameter:
2459: . mesh - The DMPlex
2461: Output Parameter:
2463: Note:
2464: This should be called after all calls to DMPlexSetCone()
2466: Level: beginner
2468: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2469: @*/
2470: PetscErrorCode DMPlexSymmetrize(DM dm)
2471: {
2472: DM_Plex *mesh = (DM_Plex*) dm->data;
2473: PetscInt *offsets;
2474: PetscInt supportSize;
2475: PetscInt pStart, pEnd, p;
2480: if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2481: /* Calculate support sizes */
2482: DMPlexGetChart(dm, &pStart, &pEnd);
2483: for (p = pStart; p < pEnd; ++p) {
2484: PetscInt dof, off, c;
2486: PetscSectionGetDof(mesh->coneSection, p, &dof);
2487: PetscSectionGetOffset(mesh->coneSection, p, &off);
2488: for (c = off; c < off+dof; ++c) {
2489: PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2490: }
2491: }
2492: for (p = pStart; p < pEnd; ++p) {
2493: PetscInt dof;
2495: PetscSectionGetDof(mesh->supportSection, p, &dof);
2497: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2498: }
2499: PetscSectionSetUp(mesh->supportSection);
2500: /* Calculate supports */
2501: PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2502: PetscMalloc1(supportSize, &mesh->supports);
2503: PetscCalloc1(pEnd - pStart, &offsets);
2504: for (p = pStart; p < pEnd; ++p) {
2505: PetscInt dof, off, c;
2507: PetscSectionGetDof(mesh->coneSection, p, &dof);
2508: PetscSectionGetOffset(mesh->coneSection, p, &off);
2509: for (c = off; c < off+dof; ++c) {
2510: const PetscInt q = mesh->cones[c];
2511: PetscInt offS;
2513: PetscSectionGetOffset(mesh->supportSection, q, &offS);
2515: mesh->supports[offS+offsets[q]] = p;
2516: ++offsets[q];
2517: }
2518: }
2519: PetscFree(offsets);
2520: return(0);
2521: }
2523: static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt);
2525: /*@
2526: DMPlexStratify - The DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2527: can be illustrated by a Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2528: same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2529: the DAG.
2531: Collective on dm
2533: Input Parameter:
2534: . mesh - The DMPlex
2536: Output Parameter:
2538: Notes:
2539: Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2540: 1 for edges, and so on. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2541: manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed
2542: via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1.
2544: DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
2546: Level: beginner
2548: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2549: @*/
2550: PetscErrorCode DMPlexStratify(DM dm)
2551: {
2552: DM_Plex *mesh = (DM_Plex*) dm->data;
2553: DMLabel label;
2554: PetscInt pStart, pEnd, p;
2555: PetscInt numRoots = 0, numLeaves = 0;
2556: PetscInt cMax, fMax, eMax, vMax;
2561: PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2562: /* Calculate depth */
2563: DMPlexGetChart(dm, &pStart, &pEnd);
2564: DMCreateLabel(dm, "depth");
2565: DMPlexGetDepthLabel(dm, &label);
2566: /* Initialize roots and count leaves */
2567: for (p = pStart; p < pEnd; ++p) {
2568: PetscInt coneSize, supportSize;
2570: DMPlexGetConeSize(dm, p, &coneSize);
2571: DMPlexGetSupportSize(dm, p, &supportSize);
2572: if (!coneSize && supportSize) {
2573: ++numRoots;
2574: DMLabelSetValue(label, p, 0);
2575: } else if (!supportSize && coneSize) {
2576: ++numLeaves;
2577: } else if (!supportSize && !coneSize) {
2578: /* Isolated points */
2579: DMLabelSetValue(label, p, 0);
2580: }
2581: }
2582: if (numRoots + numLeaves == (pEnd - pStart)) {
2583: for (p = pStart; p < pEnd; ++p) {
2584: PetscInt coneSize, supportSize;
2586: DMPlexGetConeSize(dm, p, &coneSize);
2587: DMPlexGetSupportSize(dm, p, &supportSize);
2588: if (!supportSize && coneSize) {
2589: DMLabelSetValue(label, p, 1);
2590: }
2591: }
2592: } else {
2593: IS pointIS;
2594: PetscInt numPoints = 0, level = 0;
2596: DMLabelGetStratumIS(label, level, &pointIS);
2597: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2598: while (numPoints) {
2599: const PetscInt *points;
2600: const PetscInt newLevel = level+1;
2602: ISGetIndices(pointIS, &points);
2603: for (p = 0; p < numPoints; ++p) {
2604: const PetscInt point = points[p];
2605: const PetscInt *support;
2606: PetscInt supportSize, s;
2608: DMPlexGetSupportSize(dm, point, &supportSize);
2609: DMPlexGetSupport(dm, point, &support);
2610: for (s = 0; s < supportSize; ++s) {
2611: DMLabelSetValue(label, support[s], newLevel);
2612: }
2613: }
2614: ISRestoreIndices(pointIS, &points);
2615: ++level;
2616: ISDestroy(&pointIS);
2617: DMLabelGetStratumIS(label, level, &pointIS);
2618: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2619: else {numPoints = 0;}
2620: }
2621: ISDestroy(&pointIS);
2622: }
2623: { /* just in case there is an empty process */
2624: PetscInt numValues, maxValues = 0, v;
2626: DMLabelGetNumValues(label,&numValues);
2627: for (v = 0; v < numValues; v++) {
2628: IS pointIS;
2630: DMLabelGetStratumIS(label, v, &pointIS);
2631: if (pointIS) {
2632: PetscInt min, max, numPoints;
2633: PetscInt start;
2634: PetscBool contig;
2636: ISGetLocalSize(pointIS, &numPoints);
2637: ISGetMinMax(pointIS, &min, &max);
2638: ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2639: if (start == 0 && contig) {
2640: ISDestroy(&pointIS);
2641: ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2642: DMLabelSetStratumIS(label, v, pointIS);
2643: }
2644: }
2645: ISDestroy(&pointIS);
2646: }
2647: MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2648: for (v = numValues; v < maxValues; v++) {
2649: DMLabelAddStratum(label,v);
2650: }
2651: }
2652: PetscObjectStateGet((PetscObject) label, &mesh->depthState);
2654: DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2655: if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2656: DMLabel dimLabel;
2657: PetscInt dim;
2659: DMGetDimension(dm, &dim);
2660: DMGetLabel(dm, "dim", &dimLabel);
2661: if (!dimLabel) {
2662: DMCreateLabel(dm, "dim");
2663: DMGetLabel(dm, "dim", &dimLabel);
2664: }
2665: if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2666: if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2667: if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2668: if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2669: }
2670: PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2671: return(0);
2672: }
2674: /*@C
2675: DMPlexGetJoin - Get an array for the join of the set of points
2677: Not Collective
2679: Input Parameters:
2680: + dm - The DMPlex object
2681: . numPoints - The number of input points for the join
2682: - points - The input points
2684: Output Parameters:
2685: + numCoveredPoints - The number of points in the join
2686: - coveredPoints - The points in the join
2688: Level: intermediate
2690: Note: Currently, this is restricted to a single level join
2692: Fortran Notes:
2693: Since it returns an array, this routine is only available in Fortran 90, and you must
2694: include petsc.h90 in your code.
2696: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2698: .keywords: mesh
2699: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2700: @*/
2701: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2702: {
2703: DM_Plex *mesh = (DM_Plex*) dm->data;
2704: PetscInt *join[2];
2705: PetscInt joinSize, i = 0;
2706: PetscInt dof, off, p, c, m;
2714: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2715: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2716: /* Copy in support of first point */
2717: PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2718: PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2719: for (joinSize = 0; joinSize < dof; ++joinSize) {
2720: join[i][joinSize] = mesh->supports[off+joinSize];
2721: }
2722: /* Check each successive support */
2723: for (p = 1; p < numPoints; ++p) {
2724: PetscInt newJoinSize = 0;
2726: PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2727: PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2728: for (c = 0; c < dof; ++c) {
2729: const PetscInt point = mesh->supports[off+c];
2731: for (m = 0; m < joinSize; ++m) {
2732: if (point == join[i][m]) {
2733: join[1-i][newJoinSize++] = point;
2734: break;
2735: }
2736: }
2737: }
2738: joinSize = newJoinSize;
2739: i = 1-i;
2740: }
2741: *numCoveredPoints = joinSize;
2742: *coveredPoints = join[i];
2743: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2744: return(0);
2745: }
2747: /*@C
2748: DMPlexRestoreJoin - Restore an array for the join of the set of points
2750: Not Collective
2752: Input Parameters:
2753: + dm - The DMPlex object
2754: . numPoints - The number of input points for the join
2755: - points - The input points
2757: Output Parameters:
2758: + numCoveredPoints - The number of points in the join
2759: - coveredPoints - The points in the join
2761: Fortran Notes:
2762: Since it returns an array, this routine is only available in Fortran 90, and you must
2763: include petsc.h90 in your code.
2765: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2767: Level: intermediate
2769: .keywords: mesh
2770: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2771: @*/
2772: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2773: {
2781: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2782: if (numCoveredPoints) *numCoveredPoints = 0;
2783: return(0);
2784: }
2786: /*@C
2787: DMPlexGetFullJoin - Get an array for the join of the set of points
2789: Not Collective
2791: Input Parameters:
2792: + dm - The DMPlex object
2793: . numPoints - The number of input points for the join
2794: - points - The input points
2796: Output Parameters:
2797: + numCoveredPoints - The number of points in the join
2798: - coveredPoints - The points in the join
2800: Fortran Notes:
2801: Since it returns an array, this routine is only available in Fortran 90, and you must
2802: include petsc.h90 in your code.
2804: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2806: Level: intermediate
2808: .keywords: mesh
2809: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2810: @*/
2811: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2812: {
2813: DM_Plex *mesh = (DM_Plex*) dm->data;
2814: PetscInt *offsets, **closures;
2815: PetscInt *join[2];
2816: PetscInt depth = 0, maxSize, joinSize = 0, i = 0;
2817: PetscInt p, d, c, m, ms;
2826: DMPlexGetDepth(dm, &depth);
2827: PetscCalloc1(numPoints, &closures);
2828: DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2829: ms = mesh->maxSupportSize;
2830: maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2831: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2832: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);
2834: for (p = 0; p < numPoints; ++p) {
2835: PetscInt closureSize;
2837: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);
2839: offsets[p*(depth+2)+0] = 0;
2840: for (d = 0; d < depth+1; ++d) {
2841: PetscInt pStart, pEnd, i;
2843: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2844: for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2845: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2846: offsets[p*(depth+2)+d+1] = i;
2847: break;
2848: }
2849: }
2850: if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2851: }
2852: 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);
2853: }
2854: for (d = 0; d < depth+1; ++d) {
2855: PetscInt dof;
2857: /* Copy in support of first point */
2858: dof = offsets[d+1] - offsets[d];
2859: for (joinSize = 0; joinSize < dof; ++joinSize) {
2860: join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2861: }
2862: /* Check each successive cone */
2863: for (p = 1; p < numPoints && joinSize; ++p) {
2864: PetscInt newJoinSize = 0;
2866: dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2867: for (c = 0; c < dof; ++c) {
2868: const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2870: for (m = 0; m < joinSize; ++m) {
2871: if (point == join[i][m]) {
2872: join[1-i][newJoinSize++] = point;
2873: break;
2874: }
2875: }
2876: }
2877: joinSize = newJoinSize;
2878: i = 1-i;
2879: }
2880: if (joinSize) break;
2881: }
2882: *numCoveredPoints = joinSize;
2883: *coveredPoints = join[i];
2884: for (p = 0; p < numPoints; ++p) {
2885: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2886: }
2887: PetscFree(closures);
2888: DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2889: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2890: return(0);
2891: }
2893: /*@C
2894: DMPlexGetMeet - Get an array for the meet of the set of points
2896: Not Collective
2898: Input Parameters:
2899: + dm - The DMPlex object
2900: . numPoints - The number of input points for the meet
2901: - points - The input points
2903: Output Parameters:
2904: + numCoveredPoints - The number of points in the meet
2905: - coveredPoints - The points in the meet
2907: Level: intermediate
2909: Note: Currently, this is restricted to a single level meet
2911: Fortran Notes:
2912: Since it returns an array, this routine is only available in Fortran 90, and you must
2913: include petsc.h90 in your code.
2915: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2917: .keywords: mesh
2918: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2919: @*/
2920: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2921: {
2922: DM_Plex *mesh = (DM_Plex*) dm->data;
2923: PetscInt *meet[2];
2924: PetscInt meetSize, i = 0;
2925: PetscInt dof, off, p, c, m;
2933: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2934: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2935: /* Copy in cone of first point */
2936: PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2937: PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2938: for (meetSize = 0; meetSize < dof; ++meetSize) {
2939: meet[i][meetSize] = mesh->cones[off+meetSize];
2940: }
2941: /* Check each successive cone */
2942: for (p = 1; p < numPoints; ++p) {
2943: PetscInt newMeetSize = 0;
2945: PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2946: PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2947: for (c = 0; c < dof; ++c) {
2948: const PetscInt point = mesh->cones[off+c];
2950: for (m = 0; m < meetSize; ++m) {
2951: if (point == meet[i][m]) {
2952: meet[1-i][newMeetSize++] = point;
2953: break;
2954: }
2955: }
2956: }
2957: meetSize = newMeetSize;
2958: i = 1-i;
2959: }
2960: *numCoveringPoints = meetSize;
2961: *coveringPoints = meet[i];
2962: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2963: return(0);
2964: }
2966: /*@C
2967: DMPlexRestoreMeet - Restore an array for the meet of the set of points
2969: Not Collective
2971: Input Parameters:
2972: + dm - The DMPlex object
2973: . numPoints - The number of input points for the meet
2974: - points - The input points
2976: Output Parameters:
2977: + numCoveredPoints - The number of points in the meet
2978: - coveredPoints - The points in the meet
2980: Level: intermediate
2982: Fortran Notes:
2983: Since it returns an array, this routine is only available in Fortran 90, and you must
2984: include petsc.h90 in your code.
2986: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2988: .keywords: mesh
2989: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2990: @*/
2991: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2992: {
3000: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3001: if (numCoveredPoints) *numCoveredPoints = 0;
3002: return(0);
3003: }
3005: /*@C
3006: DMPlexGetFullMeet - Get an array for the meet of the set of points
3008: Not Collective
3010: Input Parameters:
3011: + dm - The DMPlex object
3012: . numPoints - The number of input points for the meet
3013: - points - The input points
3015: Output Parameters:
3016: + numCoveredPoints - The number of points in the meet
3017: - coveredPoints - The points in the meet
3019: Level: intermediate
3021: Fortran Notes:
3022: Since it returns an array, this routine is only available in Fortran 90, and you must
3023: include petsc.h90 in your code.
3025: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3027: .keywords: mesh
3028: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3029: @*/
3030: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3031: {
3032: DM_Plex *mesh = (DM_Plex*) dm->data;
3033: PetscInt *offsets, **closures;
3034: PetscInt *meet[2];
3035: PetscInt height = 0, maxSize, meetSize = 0, i = 0;
3036: PetscInt p, h, c, m, mc;
3045: DMPlexGetDepth(dm, &height);
3046: PetscMalloc1(numPoints, &closures);
3047: DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3048: mc = mesh->maxConeSize;
3049: maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3050: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3051: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);
3053: for (p = 0; p < numPoints; ++p) {
3054: PetscInt closureSize;
3056: DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);
3058: offsets[p*(height+2)+0] = 0;
3059: for (h = 0; h < height+1; ++h) {
3060: PetscInt pStart, pEnd, i;
3062: DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3063: for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3064: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3065: offsets[p*(height+2)+h+1] = i;
3066: break;
3067: }
3068: }
3069: if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3070: }
3071: 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);
3072: }
3073: for (h = 0; h < height+1; ++h) {
3074: PetscInt dof;
3076: /* Copy in cone of first point */
3077: dof = offsets[h+1] - offsets[h];
3078: for (meetSize = 0; meetSize < dof; ++meetSize) {
3079: meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3080: }
3081: /* Check each successive cone */
3082: for (p = 1; p < numPoints && meetSize; ++p) {
3083: PetscInt newMeetSize = 0;
3085: dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
3086: for (c = 0; c < dof; ++c) {
3087: const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
3089: for (m = 0; m < meetSize; ++m) {
3090: if (point == meet[i][m]) {
3091: meet[1-i][newMeetSize++] = point;
3092: break;
3093: }
3094: }
3095: }
3096: meetSize = newMeetSize;
3097: i = 1-i;
3098: }
3099: if (meetSize) break;
3100: }
3101: *numCoveredPoints = meetSize;
3102: *coveredPoints = meet[i];
3103: for (p = 0; p < numPoints; ++p) {
3104: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3105: }
3106: PetscFree(closures);
3107: DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3108: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3109: return(0);
3110: }
3112: /*@C
3113: DMPlexEqual - Determine if two DMs have the same topology
3115: Not Collective
3117: Input Parameters:
3118: + dmA - A DMPlex object
3119: - dmB - A DMPlex object
3121: Output Parameters:
3122: . equal - PETSC_TRUE if the topologies are identical
3124: Level: intermediate
3126: Notes:
3127: We are not solving graph isomorphism, so we do not permutation.
3129: .keywords: mesh
3130: .seealso: DMPlexGetCone()
3131: @*/
3132: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3133: {
3134: PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
3142: *equal = PETSC_FALSE;
3143: DMPlexGetDepth(dmA, &depth);
3144: DMPlexGetDepth(dmB, &depthB);
3145: if (depth != depthB) return(0);
3146: DMPlexGetChart(dmA, &pStart, &pEnd);
3147: DMPlexGetChart(dmB, &pStartB, &pEndB);
3148: if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3149: for (p = pStart; p < pEnd; ++p) {
3150: const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3151: PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s;
3153: DMPlexGetConeSize(dmA, p, &coneSize);
3154: DMPlexGetCone(dmA, p, &cone);
3155: DMPlexGetConeOrientation(dmA, p, &ornt);
3156: DMPlexGetConeSize(dmB, p, &coneSizeB);
3157: DMPlexGetCone(dmB, p, &coneB);
3158: DMPlexGetConeOrientation(dmB, p, &orntB);
3159: if (coneSize != coneSizeB) return(0);
3160: for (c = 0; c < coneSize; ++c) {
3161: if (cone[c] != coneB[c]) return(0);
3162: if (ornt[c] != orntB[c]) return(0);
3163: }
3164: DMPlexGetSupportSize(dmA, p, &supportSize);
3165: DMPlexGetSupport(dmA, p, &support);
3166: DMPlexGetSupportSize(dmB, p, &supportSizeB);
3167: DMPlexGetSupport(dmB, p, &supportB);
3168: if (supportSize != supportSizeB) return(0);
3169: for (s = 0; s < supportSize; ++s) {
3170: if (support[s] != supportB[s]) return(0);
3171: }
3172: }
3173: *equal = PETSC_TRUE;
3174: return(0);
3175: }
3177: /*@C
3178: DMPlexGetNumFaceVertices - Returns the number of vertices on a face
3180: Not Collective
3182: Input Parameters:
3183: + dm - The DMPlex
3184: . cellDim - The cell dimension
3185: - numCorners - The number of vertices on a cell
3187: Output Parameters:
3188: . numFaceVertices - The number of vertices on a face
3190: Level: developer
3192: Notes:
3193: Of course this can only work for a restricted set of symmetric shapes
3195: .seealso: DMPlexGetCone()
3196: @*/
3197: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3198: {
3199: MPI_Comm comm;
3203: PetscObjectGetComm((PetscObject)dm,&comm);
3205: switch (cellDim) {
3206: case 0:
3207: *numFaceVertices = 0;
3208: break;
3209: case 1:
3210: *numFaceVertices = 1;
3211: break;
3212: case 2:
3213: switch (numCorners) {
3214: case 3: /* triangle */
3215: *numFaceVertices = 2; /* Edge has 2 vertices */
3216: break;
3217: case 4: /* quadrilateral */
3218: *numFaceVertices = 2; /* Edge has 2 vertices */
3219: break;
3220: case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3221: *numFaceVertices = 3; /* Edge has 3 vertices */
3222: break;
3223: case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3224: *numFaceVertices = 3; /* Edge has 3 vertices */
3225: break;
3226: default:
3227: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3228: }
3229: break;
3230: case 3:
3231: switch (numCorners) {
3232: case 4: /* tetradehdron */
3233: *numFaceVertices = 3; /* Face has 3 vertices */
3234: break;
3235: case 6: /* tet cohesive cells */
3236: *numFaceVertices = 4; /* Face has 4 vertices */
3237: break;
3238: case 8: /* hexahedron */
3239: *numFaceVertices = 4; /* Face has 4 vertices */
3240: break;
3241: case 9: /* tet cohesive Lagrange cells */
3242: *numFaceVertices = 6; /* Face has 6 vertices */
3243: break;
3244: case 10: /* quadratic tetrahedron */
3245: *numFaceVertices = 6; /* Face has 6 vertices */
3246: break;
3247: case 12: /* hex cohesive Lagrange cells */
3248: *numFaceVertices = 6; /* Face has 6 vertices */
3249: break;
3250: case 18: /* quadratic tet cohesive Lagrange cells */
3251: *numFaceVertices = 6; /* Face has 6 vertices */
3252: break;
3253: case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3254: *numFaceVertices = 9; /* Face has 9 vertices */
3255: break;
3256: default:
3257: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3258: }
3259: break;
3260: default:
3261: SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3262: }
3263: return(0);
3264: }
3266: /*@
3267: DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
3269: Not Collective
3271: Input Parameter:
3272: . dm - The DMPlex object
3274: Output Parameter:
3275: . depthLabel - The DMLabel recording point depth
3277: Level: developer
3279: .keywords: mesh, points
3280: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3281: @*/
3282: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3283: {
3289: if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3290: *depthLabel = dm->depthLabel;
3291: return(0);
3292: }
3294: /*@
3295: DMPlexGetDepth - Get the depth of the DAG representing this mesh
3297: Not Collective
3299: Input Parameter:
3300: . dm - The DMPlex object
3302: Output Parameter:
3303: . depth - The number of strata (breadth first levels) in the DAG
3305: Level: developer
3307: .keywords: mesh, points
3308: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3309: @*/
3310: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3311: {
3312: DMLabel label;
3313: PetscInt d = 0;
3319: DMPlexGetDepthLabel(dm, &label);
3320: if (label) {DMLabelGetNumValues(label, &d);}
3321: *depth = d-1;
3322: return(0);
3323: }
3325: /*@
3326: DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
3328: Not Collective
3330: Input Parameters:
3331: + dm - The DMPlex object
3332: - stratumValue - The requested depth
3334: Output Parameters:
3335: + start - The first point at this depth
3336: - end - One beyond the last point at this depth
3338: Level: developer
3340: .keywords: mesh, points
3341: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3342: @*/
3343: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3344: {
3345: DMLabel label;
3346: PetscInt pStart, pEnd;
3353: DMPlexGetChart(dm, &pStart, &pEnd);
3354: if (pStart == pEnd) return(0);
3355: if (stratumValue < 0) {
3356: if (start) *start = pStart;
3357: if (end) *end = pEnd;
3358: return(0);
3359: }
3360: DMPlexGetDepthLabel(dm, &label);
3361: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3362: DMLabelGetStratumBounds(label, stratumValue, start, end);
3363: return(0);
3364: }
3366: /*@
3367: DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3369: Not Collective
3371: Input Parameters:
3372: + dm - The DMPlex object
3373: - stratumValue - The requested height
3375: Output Parameters:
3376: + start - The first point at this height
3377: - end - One beyond the last point at this height
3379: Level: developer
3381: .keywords: mesh, points
3382: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3383: @*/
3384: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3385: {
3386: DMLabel label;
3387: PetscInt depth, pStart, pEnd;
3394: DMPlexGetChart(dm, &pStart, &pEnd);
3395: if (pStart == pEnd) return(0);
3396: if (stratumValue < 0) {
3397: if (start) *start = pStart;
3398: if (end) *end = pEnd;
3399: return(0);
3400: }
3401: DMPlexGetDepthLabel(dm, &label);
3402: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3403: DMLabelGetNumValues(label, &depth);
3404: DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3405: return(0);
3406: }
3408: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3409: {
3410: PetscSection section, s;
3411: Mat m;
3412: PetscInt maxHeight;
3416: DMClone(dm, cdm);
3417: DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3418: DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3419: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
3420: DMSetSection(*cdm, section);
3421: PetscSectionDestroy(§ion);
3422: PetscSectionCreate(PETSC_COMM_SELF, &s);
3423: MatCreate(PETSC_COMM_SELF, &m);
3424: DMSetDefaultConstraints(*cdm, s, m);
3425: PetscSectionDestroy(&s);
3426: MatDestroy(&m);
3428: DMSetNumFields(*cdm, 1);
3429: DMCreateDS(*cdm);
3430: return(0);
3431: }
3433: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3434: {
3435: Vec coordsLocal;
3436: DM coordsDM;
3440: *field = NULL;
3441: DMGetCoordinatesLocal(dm,&coordsLocal);
3442: DMGetCoordinateDM(dm,&coordsDM);
3443: if (coordsLocal && coordsDM) {
3444: DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3445: }
3446: return(0);
3447: }
3449: /*@C
3450: DMPlexGetConeSection - Return a section which describes the layout of cone data
3452: Not Collective
3454: Input Parameters:
3455: . dm - The DMPlex object
3457: Output Parameter:
3458: . section - The PetscSection object
3460: Level: developer
3462: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3463: @*/
3464: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3465: {
3466: DM_Plex *mesh = (DM_Plex*) dm->data;
3470: if (section) *section = mesh->coneSection;
3471: return(0);
3472: }
3474: /*@C
3475: DMPlexGetSupportSection - Return a section which describes the layout of support data
3477: Not Collective
3479: Input Parameters:
3480: . dm - The DMPlex object
3482: Output Parameter:
3483: . section - The PetscSection object
3485: Level: developer
3487: .seealso: DMPlexGetConeSection()
3488: @*/
3489: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3490: {
3491: DM_Plex *mesh = (DM_Plex*) dm->data;
3495: if (section) *section = mesh->supportSection;
3496: return(0);
3497: }
3499: /*@C
3500: DMPlexGetCones - Return cone data
3502: Not Collective
3504: Input Parameters:
3505: . dm - The DMPlex object
3507: Output Parameter:
3508: . cones - The cone for each point
3510: Level: developer
3512: .seealso: DMPlexGetConeSection()
3513: @*/
3514: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3515: {
3516: DM_Plex *mesh = (DM_Plex*) dm->data;
3520: if (cones) *cones = mesh->cones;
3521: return(0);
3522: }
3524: /*@C
3525: DMPlexGetConeOrientations - Return cone orientation data
3527: Not Collective
3529: Input Parameters:
3530: . dm - The DMPlex object
3532: Output Parameter:
3533: . coneOrientations - The cone orientation for each point
3535: Level: developer
3537: .seealso: DMPlexGetConeSection()
3538: @*/
3539: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3540: {
3541: DM_Plex *mesh = (DM_Plex*) dm->data;
3545: if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3546: return(0);
3547: }
3549: /******************************** FEM Support **********************************/
3551: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3552: {
3553: DMLabel label;
3554: PetscInt *perm;
3555: PetscInt dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3559: if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3560: DMGetDimension(dm, &dim);
3561: DMPlexGetDepthLabel(dm, &label);
3562: DMLabelGetValue(label, point, &depth);
3563: if (depth == 1) {eStart = point;}
3564: else if (depth == dim) {
3565: const PetscInt *cone;
3567: DMPlexGetCone(dm, point, &cone);
3568: if (dim == 2) eStart = cone[0];
3569: else if (dim == 3) {
3570: const PetscInt *cone2;
3571: DMPlexGetCone(dm, cone[0], &cone2);
3572: eStart = cone2[0];
3573: } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim);
3574: } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim);
3575: if (!section) {DMGetSection(dm, §ion);}
3576: PetscSectionGetNumFields(section, &Nf);
3577: if (dim <= 1) return(0);
3578: for (f = 0; f < Nf; ++f) {
3579: /* An order k SEM disc has k-1 dofs on an edge */
3580: PetscSectionGetFieldDof(section, eStart, f, &k);
3581: PetscSectionGetFieldComponents(section, f, &Nc);
3582: k = k/Nc + 1;
3583: size += PetscPowInt(k+1, dim)*Nc;
3584: }
3585: PetscMalloc1(size, &perm);
3586: for (f = 0; f < Nf; ++f) {
3587: switch (dim) {
3588: case 2:
3589: /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3590: PetscSectionGetFieldDof(section, eStart, f, &k);
3591: PetscSectionGetFieldComponents(section, f, &Nc);
3592: k = k/Nc + 1;
3593: /* The SEM order is
3595: v_lb, {e_b}, v_rb,
3596: e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3597: v_lt, reverse {e_t}, v_rt
3598: */
3599: {
3600: const PetscInt of = 0;
3601: const PetscInt oeb = of + PetscSqr(k-1);
3602: const PetscInt oer = oeb + (k-1);
3603: const PetscInt oet = oer + (k-1);
3604: const PetscInt oel = oet + (k-1);
3605: const PetscInt ovlb = oel + (k-1);
3606: const PetscInt ovrb = ovlb + 1;
3607: const PetscInt ovrt = ovrb + 1;
3608: const PetscInt ovlt = ovrt + 1;
3609: PetscInt o;
3611: /* bottom */
3612: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3613: for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3614: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3615: /* middle */
3616: for (i = 0; i < k-1; ++i) {
3617: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3618: 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;
3619: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3620: }
3621: /* top */
3622: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3623: for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3624: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3625: foffset = offset;
3626: }
3627: break;
3628: case 3:
3629: /* The original hex closure is
3631: {c,
3632: f_b, f_t, f_f, f_b, f_r, f_l,
3633: e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb,
3634: v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3635: */
3636: PetscSectionGetFieldDof(section, eStart, f, &k);
3637: PetscSectionGetFieldComponents(section, f, &Nc);
3638: k = k/Nc + 1;
3639: /* The SEM order is
3640: Bottom Slice
3641: v_blf, {e^{(k-1)-n}_bf}, v_brf,
3642: e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3643: v_blb, {e_bb}, v_brb,
3645: Middle Slice (j)
3646: {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3647: f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3648: e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3650: Top Slice
3651: v_tlf, {e_tf}, v_trf,
3652: e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3653: v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3654: */
3655: {
3656: const PetscInt oc = 0;
3657: const PetscInt ofb = oc + PetscSqr(k-1)*(k-1);
3658: const PetscInt oft = ofb + PetscSqr(k-1);
3659: const PetscInt off = oft + PetscSqr(k-1);
3660: const PetscInt ofk = off + PetscSqr(k-1);
3661: const PetscInt ofr = ofk + PetscSqr(k-1);
3662: const PetscInt ofl = ofr + PetscSqr(k-1);
3663: const PetscInt oebl = ofl + PetscSqr(k-1);
3664: const PetscInt oebb = oebl + (k-1);
3665: const PetscInt oebr = oebb + (k-1);
3666: const PetscInt oebf = oebr + (k-1);
3667: const PetscInt oetf = oebf + (k-1);
3668: const PetscInt oetr = oetf + (k-1);
3669: const PetscInt oetb = oetr + (k-1);
3670: const PetscInt oetl = oetb + (k-1);
3671: const PetscInt oerf = oetl + (k-1);
3672: const PetscInt oelf = oerf + (k-1);
3673: const PetscInt oelb = oelf + (k-1);
3674: const PetscInt oerb = oelb + (k-1);
3675: const PetscInt ovblf = oerb + (k-1);
3676: const PetscInt ovblb = ovblf + 1;
3677: const PetscInt ovbrb = ovblb + 1;
3678: const PetscInt ovbrf = ovbrb + 1;
3679: const PetscInt ovtlf = ovbrf + 1;
3680: const PetscInt ovtrf = ovtlf + 1;
3681: const PetscInt ovtrb = ovtrf + 1;
3682: const PetscInt ovtlb = ovtrb + 1;
3683: PetscInt o, n;
3685: /* Bottom Slice */
3686: /* bottom */
3687: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3688: for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3689: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3690: /* middle */
3691: for (i = 0; i < k-1; ++i) {
3692: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3693: 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;}
3694: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3695: }
3696: /* top */
3697: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3698: for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3699: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
3701: /* Middle Slice */
3702: for (j = 0; j < k-1; ++j) {
3703: /* bottom */
3704: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3705: 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;
3706: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3707: /* middle */
3708: for (i = 0; i < k-1; ++i) {
3709: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3710: 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;
3711: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3712: }
3713: /* top */
3714: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3715: 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;
3716: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3717: }
3719: /* Top Slice */
3720: /* bottom */
3721: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3722: for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3723: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3724: /* middle */
3725: for (i = 0; i < k-1; ++i) {
3726: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3727: for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3728: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3729: }
3730: /* top */
3731: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3732: for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3733: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
3735: foffset = offset;
3736: }
3737: break;
3738: default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3739: }
3740: }
3741: if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3742: /* Check permutation */
3743: {
3744: PetscInt *check;
3746: PetscMalloc1(size, &check);
3747: 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]);}
3748: for (i = 0; i < size; ++i) check[perm[i]] = i;
3749: for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3750: PetscFree(check);
3751: }
3752: PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3753: return(0);
3754: }
3756: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3757: {
3758: PetscDS prob;
3759: PetscInt depth, Nf, h;
3760: DMLabel label;
3764: DMGetDS(dm, &prob);
3765: Nf = prob->Nf;
3766: label = dm->depthLabel;
3767: *dspace = NULL;
3768: if (field < Nf) {
3769: PetscObject disc = prob->disc[field];
3771: if (disc->classid == PETSCFE_CLASSID) {
3772: PetscDualSpace dsp;
3774: PetscFEGetDualSpace((PetscFE)disc,&dsp);
3775: DMLabelGetNumValues(label,&depth);
3776: DMLabelGetValue(label,point,&h);
3777: h = depth - 1 - h;
3778: if (h) {
3779: PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3780: } else {
3781: *dspace = dsp;
3782: }
3783: }
3784: }
3785: return(0);
3786: }
3789: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3790: {
3791: PetscScalar *array, *vArray;
3792: const PetscInt *cone, *coneO;
3793: PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0;
3794: PetscErrorCode ierr;
3797: PetscSectionGetChart(section, &pStart, &pEnd);
3798: DMPlexGetConeSize(dm, point, &numPoints);
3799: DMPlexGetCone(dm, point, &cone);
3800: DMPlexGetConeOrientation(dm, point, &coneO);
3801: if (!values || !*values) {
3802: if ((point >= pStart) && (point < pEnd)) {
3803: PetscInt dof;
3805: PetscSectionGetDof(section, point, &dof);
3806: size += dof;
3807: }
3808: for (p = 0; p < numPoints; ++p) {
3809: const PetscInt cp = cone[p];
3810: PetscInt dof;
3812: if ((cp < pStart) || (cp >= pEnd)) continue;
3813: PetscSectionGetDof(section, cp, &dof);
3814: size += dof;
3815: }
3816: if (!values) {
3817: if (csize) *csize = size;
3818: return(0);
3819: }
3820: DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
3821: } else {
3822: array = *values;
3823: }
3824: size = 0;
3825: VecGetArray(v, &vArray);
3826: if ((point >= pStart) && (point < pEnd)) {
3827: PetscInt dof, off, d;
3828: PetscScalar *varr;
3830: PetscSectionGetDof(section, point, &dof);
3831: PetscSectionGetOffset(section, point, &off);
3832: varr = &vArray[off];
3833: for (d = 0; d < dof; ++d, ++offset) {
3834: array[offset] = varr[d];
3835: }
3836: size += dof;
3837: }
3838: for (p = 0; p < numPoints; ++p) {
3839: const PetscInt cp = cone[p];
3840: PetscInt o = coneO[p];
3841: PetscInt dof, off, d;
3842: PetscScalar *varr;
3844: if ((cp < pStart) || (cp >= pEnd)) continue;
3845: PetscSectionGetDof(section, cp, &dof);
3846: PetscSectionGetOffset(section, cp, &off);
3847: varr = &vArray[off];
3848: if (o >= 0) {
3849: for (d = 0; d < dof; ++d, ++offset) {
3850: array[offset] = varr[d];
3851: }
3852: } else {
3853: for (d = dof-1; d >= 0; --d, ++offset) {
3854: array[offset] = varr[d];
3855: }
3856: }
3857: size += dof;
3858: }
3859: VecRestoreArray(v, &vArray);
3860: if (!*values) {
3861: if (csize) *csize = size;
3862: *values = array;
3863: } else {
3864: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3865: *csize = size;
3866: }
3867: return(0);
3868: }
3870: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3871: {
3872: const PetscInt *cla;
3873: PetscInt np, *pts = NULL;
3877: PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3878: if (!*clPoints) {
3879: PetscInt pStart, pEnd, p, q;
3881: PetscSectionGetChart(section, &pStart, &pEnd);
3882: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3883: /* Compress out points not in the section */
3884: for (p = 0, q = 0; p < np; p++) {
3885: PetscInt r = pts[2*p];
3886: if ((r >= pStart) && (r < pEnd)) {
3887: pts[q*2] = r;
3888: pts[q*2+1] = pts[2*p+1];
3889: ++q;
3890: }
3891: }
3892: np = q;
3893: cla = NULL;
3894: } else {
3895: PetscInt dof, off;
3897: PetscSectionGetDof(*clSec, point, &dof);
3898: PetscSectionGetOffset(*clSec, point, &off);
3899: ISGetIndices(*clPoints, &cla);
3900: np = dof/2;
3901: pts = (PetscInt *) &cla[off];
3902: }
3903: *numPoints = np;
3904: *points = pts;
3905: *clp = cla;
3907: return(0);
3908: }
3910: static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3911: {
3915: if (!*clPoints) {
3916: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3917: } else {
3918: ISRestoreIndices(*clPoints, clp);
3919: }
3920: *numPoints = 0;
3921: *points = NULL;
3922: *clSec = NULL;
3923: *clPoints = NULL;
3924: *clp = NULL;
3925: return(0);
3926: }
3928: 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[])
3929: {
3930: PetscInt offset = 0, p;
3931: const PetscInt **perms = NULL;
3932: const PetscScalar **flips = NULL;
3933: PetscErrorCode ierr;
3936: *size = 0;
3937: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3938: for (p = 0; p < numPoints; p++) {
3939: const PetscInt point = points[2*p];
3940: const PetscInt *perm = perms ? perms[p] : NULL;
3941: const PetscScalar *flip = flips ? flips[p] : NULL;
3942: PetscInt dof, off, d;
3943: const PetscScalar *varr;
3945: PetscSectionGetDof(section, point, &dof);
3946: PetscSectionGetOffset(section, point, &off);
3947: varr = &vArray[off];
3948: if (clperm) {
3949: if (perm) {
3950: for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
3951: } else {
3952: for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d];
3953: }
3954: if (flip) {
3955: for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d];
3956: }
3957: } else {
3958: if (perm) {
3959: for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
3960: } else {
3961: for (d = 0; d < dof; d++) array[offset + d ] = varr[d];
3962: }
3963: if (flip) {
3964: for (d = 0; d < dof; d++) array[offset + d ] *= flip[d];
3965: }
3966: }
3967: offset += dof;
3968: }
3969: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3970: *size = offset;
3971: return(0);
3972: }
3974: 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[])
3975: {
3976: PetscInt offset = 0, f;
3977: PetscErrorCode ierr;
3980: *size = 0;
3981: for (f = 0; f < numFields; ++f) {
3982: PetscInt p;
3983: const PetscInt **perms = NULL;
3984: const PetscScalar **flips = NULL;
3986: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3987: for (p = 0; p < numPoints; p++) {
3988: const PetscInt point = points[2*p];
3989: PetscInt fdof, foff, b;
3990: const PetscScalar *varr;
3991: const PetscInt *perm = perms ? perms[p] : NULL;
3992: const PetscScalar *flip = flips ? flips[p] : NULL;
3994: PetscSectionGetFieldDof(section, point, f, &fdof);
3995: PetscSectionGetFieldOffset(section, point, f, &foff);
3996: varr = &vArray[foff];
3997: if (clperm) {
3998: if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}}
3999: else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}}
4000: if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}}
4001: } else {
4002: if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}}
4003: else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}}
4004: if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}}
4005: }
4006: offset += fdof;
4007: }
4008: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4009: }
4010: *size = offset;
4011: return(0);
4012: }
4014: /*@C
4015: DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4017: Not collective
4019: Input Parameters:
4020: + dm - The DM
4021: . section - The section describing the layout in v, or NULL to use the default section
4022: . v - The local vector
4023: . point - The point in the DM
4024: . csize - The size of the input values array, or NULL
4025: - values - An array to use for the values, or NULL to have it allocated automatically
4027: Output Parameters:
4028: + csize - The number of values in the closure
4029: - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4031: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4032: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4033: $ assembly function, and a user may already have allocated storage for this operation.
4034: $
4035: $ A typical use could be
4036: $
4037: $ values = NULL;
4038: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4039: $ for (cl = 0; cl < clSize; ++cl) {
4040: $ <Compute on closure>
4041: $ }
4042: $ DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4043: $
4044: $ or
4045: $
4046: $ PetscMalloc1(clMaxSize, &values);
4047: $ for (p = pStart; p < pEnd; ++p) {
4048: $ clSize = clMaxSize;
4049: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4050: $ for (cl = 0; cl < clSize; ++cl) {
4051: $ <Compute on closure>
4052: $ }
4053: $ }
4054: $ PetscFree(values);
4056: Fortran Notes:
4057: Since it returns an array, this routine is only available in Fortran 90, and you must
4058: include petsc.h90 in your code.
4060: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4062: Level: intermediate
4064: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4065: @*/
4066: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4067: {
4068: PetscSection clSection;
4069: IS clPoints;
4070: PetscScalar *array;
4071: const PetscScalar *vArray;
4072: PetscInt *points = NULL;
4073: const PetscInt *clp, *perm;
4074: PetscInt depth, numFields, numPoints, size;
4075: PetscErrorCode ierr;
4079: if (!section) {DMGetSection(dm, §ion);}
4082: DMPlexGetDepth(dm, &depth);
4083: PetscSectionGetNumFields(section, &numFields);
4084: if (depth == 1 && numFields < 2) {
4085: DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4086: return(0);
4087: }
4088: /* Get points */
4089: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4090: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4091: /* Get array */
4092: if (!values || !*values) {
4093: PetscInt asize = 0, dof, p;
4095: for (p = 0; p < numPoints*2; p += 2) {
4096: PetscSectionGetDof(section, points[p], &dof);
4097: asize += dof;
4098: }
4099: if (!values) {
4100: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4101: if (csize) *csize = asize;
4102: return(0);
4103: }
4104: DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4105: } else {
4106: array = *values;
4107: }
4108: VecGetArrayRead(v, &vArray);
4109: /* Get values */
4110: if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4111: else {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4112: /* Cleanup points */
4113: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4114: /* Cleanup array */
4115: VecRestoreArrayRead(v, &vArray);
4116: if (!*values) {
4117: if (csize) *csize = size;
4118: *values = array;
4119: } else {
4120: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4121: *csize = size;
4122: }
4123: return(0);
4124: }
4126: /*@C
4127: DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4129: Not collective
4131: Input Parameters:
4132: + dm - The DM
4133: . section - The section describing the layout in v, or NULL to use the default section
4134: . v - The local vector
4135: . point - The point in the DM
4136: . csize - The number of values in the closure, or NULL
4137: - values - The array of values, which is a borrowed array and should not be freed
4139: Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4141: Fortran Notes:
4142: Since it returns an array, this routine is only available in Fortran 90, and you must
4143: include petsc.h90 in your code.
4145: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4147: Level: intermediate
4149: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4150: @*/
4151: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4152: {
4153: PetscInt size = 0;
4157: /* Should work without recalculating size */
4158: DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4159: *values = NULL;
4160: return(0);
4161: }
4163: PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;}
4164: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;}
4166: 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[])
4167: {
4168: PetscInt cdof; /* The number of constraints on this point */
4169: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4170: PetscScalar *a;
4171: PetscInt off, cind = 0, k;
4172: PetscErrorCode ierr;
4175: PetscSectionGetConstraintDof(section, point, &cdof);
4176: PetscSectionGetOffset(section, point, &off);
4177: a = &array[off];
4178: if (!cdof || setBC) {
4179: if (clperm) {
4180: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4181: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}}
4182: } else {
4183: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4184: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}}
4185: }
4186: } else {
4187: PetscSectionGetConstraintIndices(section, point, &cdofs);
4188: if (clperm) {
4189: if (perm) {for (k = 0; k < dof; ++k) {
4190: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4191: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4192: }
4193: } else {
4194: for (k = 0; k < dof; ++k) {
4195: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4196: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4197: }
4198: }
4199: } else {
4200: if (perm) {
4201: for (k = 0; k < dof; ++k) {
4202: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4203: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4204: }
4205: } else {
4206: for (k = 0; k < dof; ++k) {
4207: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4208: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4209: }
4210: }
4211: }
4212: }
4213: return(0);
4214: }
4216: 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[])
4217: {
4218: PetscInt cdof; /* The number of constraints on this point */
4219: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4220: PetscScalar *a;
4221: PetscInt off, cind = 0, k;
4222: PetscErrorCode ierr;
4225: PetscSectionGetConstraintDof(section, point, &cdof);
4226: PetscSectionGetOffset(section, point, &off);
4227: a = &array[off];
4228: if (cdof) {
4229: PetscSectionGetConstraintIndices(section, point, &cdofs);
4230: if (clperm) {
4231: if (perm) {
4232: for (k = 0; k < dof; ++k) {
4233: if ((cind < cdof) && (k == cdofs[cind])) {
4234: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4235: cind++;
4236: }
4237: }
4238: } else {
4239: for (k = 0; k < dof; ++k) {
4240: if ((cind < cdof) && (k == cdofs[cind])) {
4241: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4242: cind++;
4243: }
4244: }
4245: }
4246: } else {
4247: if (perm) {
4248: for (k = 0; k < dof; ++k) {
4249: if ((cind < cdof) && (k == cdofs[cind])) {
4250: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4251: cind++;
4252: }
4253: }
4254: } else {
4255: for (k = 0; k < dof; ++k) {
4256: if ((cind < cdof) && (k == cdofs[cind])) {
4257: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4258: cind++;
4259: }
4260: }
4261: }
4262: }
4263: }
4264: return(0);
4265: }
4267: 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[])
4268: {
4269: PetscScalar *a;
4270: PetscInt fdof, foff, fcdof, foffset = *offset;
4271: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4272: PetscInt cind = 0, b;
4273: PetscErrorCode ierr;
4276: PetscSectionGetFieldDof(section, point, f, &fdof);
4277: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4278: PetscSectionGetFieldOffset(section, point, f, &foff);
4279: a = &array[foff];
4280: if (!fcdof || setBC) {
4281: if (clperm) {
4282: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4283: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}}
4284: } else {
4285: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4286: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}}
4287: }
4288: } else {
4289: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4290: if (clperm) {
4291: if (perm) {
4292: for (b = 0; b < fdof; b++) {
4293: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4294: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4295: }
4296: } else {
4297: for (b = 0; b < fdof; b++) {
4298: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4299: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4300: }
4301: }
4302: } else {
4303: if (perm) {
4304: for (b = 0; b < fdof; b++) {
4305: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4306: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4307: }
4308: } else {
4309: for (b = 0; b < fdof; b++) {
4310: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4311: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4312: }
4313: }
4314: }
4315: }
4316: *offset += fdof;
4317: return(0);
4318: }
4320: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4321: {
4322: PetscScalar *a;
4323: PetscInt fdof, foff, fcdof, foffset = *offset;
4324: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4325: PetscInt cind = 0, ncind = 0, b;
4326: PetscBool ncSet, fcSet;
4327: PetscErrorCode ierr;
4330: PetscSectionGetFieldDof(section, point, f, &fdof);
4331: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4332: PetscSectionGetFieldOffset(section, point, f, &foff);
4333: a = &array[foff];
4334: if (fcdof) {
4335: /* We just override fcdof and fcdofs with Ncc and comps */
4336: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4337: if (clperm) {
4338: if (perm) {
4339: if (comps) {
4340: for (b = 0; b < fdof; b++) {
4341: ncSet = fcSet = PETSC_FALSE;
4342: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4343: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4344: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4345: }
4346: } else {
4347: for (b = 0; b < fdof; b++) {
4348: if ((cind < fcdof) && (b == fcdofs[cind])) {
4349: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4350: ++cind;
4351: }
4352: }
4353: }
4354: } else {
4355: if (comps) {
4356: for (b = 0; b < fdof; b++) {
4357: ncSet = fcSet = PETSC_FALSE;
4358: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4359: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4360: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}
4361: }
4362: } else {
4363: for (b = 0; b < fdof; b++) {
4364: if ((cind < fcdof) && (b == fcdofs[cind])) {
4365: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4366: ++cind;
4367: }
4368: }
4369: }
4370: }
4371: } else {
4372: if (perm) {
4373: if (comps) {
4374: for (b = 0; b < fdof; b++) {
4375: ncSet = fcSet = PETSC_FALSE;
4376: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4377: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4378: if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4379: }
4380: } else {
4381: for (b = 0; b < fdof; b++) {
4382: if ((cind < fcdof) && (b == fcdofs[cind])) {
4383: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4384: ++cind;
4385: }
4386: }
4387: }
4388: } else {
4389: if (comps) {
4390: for (b = 0; b < fdof; b++) {
4391: ncSet = fcSet = PETSC_FALSE;
4392: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4393: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4394: if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}
4395: }
4396: } else {
4397: for (b = 0; b < fdof; b++) {
4398: if ((cind < fcdof) && (b == fcdofs[cind])) {
4399: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4400: ++cind;
4401: }
4402: }
4403: }
4404: }
4405: }
4406: }
4407: *offset += fdof;
4408: return(0);
4409: }
4411: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4412: {
4413: PetscScalar *array;
4414: const PetscInt *cone, *coneO;
4415: PetscInt pStart, pEnd, p, numPoints, off, dof;
4416: PetscErrorCode ierr;
4419: PetscSectionGetChart(section, &pStart, &pEnd);
4420: DMPlexGetConeSize(dm, point, &numPoints);
4421: DMPlexGetCone(dm, point, &cone);
4422: DMPlexGetConeOrientation(dm, point, &coneO);
4423: VecGetArray(v, &array);
4424: for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4425: const PetscInt cp = !p ? point : cone[p-1];
4426: const PetscInt o = !p ? 0 : coneO[p-1];
4428: if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4429: PetscSectionGetDof(section, cp, &dof);
4430: /* ADD_VALUES */
4431: {
4432: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4433: PetscScalar *a;
4434: PetscInt cdof, coff, cind = 0, k;
4436: PetscSectionGetConstraintDof(section, cp, &cdof);
4437: PetscSectionGetOffset(section, cp, &coff);
4438: a = &array[coff];
4439: if (!cdof) {
4440: if (o >= 0) {
4441: for (k = 0; k < dof; ++k) {
4442: a[k] += values[off+k];
4443: }
4444: } else {
4445: for (k = 0; k < dof; ++k) {
4446: a[k] += values[off+dof-k-1];
4447: }
4448: }
4449: } else {
4450: PetscSectionGetConstraintIndices(section, cp, &cdofs);
4451: if (o >= 0) {
4452: for (k = 0; k < dof; ++k) {
4453: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4454: a[k] += values[off+k];
4455: }
4456: } else {
4457: for (k = 0; k < dof; ++k) {
4458: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4459: a[k] += values[off+dof-k-1];
4460: }
4461: }
4462: }
4463: }
4464: }
4465: VecRestoreArray(v, &array);
4466: return(0);
4467: }
4469: /*@C
4470: DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4472: Not collective
4474: Input Parameters:
4475: + dm - The DM
4476: . section - The section describing the layout in v, or NULL to use the default section
4477: . v - The local vector
4478: . point - The point in the DM
4479: . values - The array of values
4480: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4481: where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
4483: Fortran Notes:
4484: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4486: Level: intermediate
4488: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4489: @*/
4490: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4491: {
4492: PetscSection clSection;
4493: IS clPoints;
4494: PetscScalar *array;
4495: PetscInt *points = NULL;
4496: const PetscInt *clp, *clperm;
4497: PetscInt depth, numFields, numPoints, p;
4498: PetscErrorCode ierr;
4502: if (!section) {DMGetSection(dm, §ion);}
4505: DMPlexGetDepth(dm, &depth);
4506: PetscSectionGetNumFields(section, &numFields);
4507: if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4508: DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4509: return(0);
4510: }
4511: /* Get points */
4512: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4513: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4514: /* Get array */
4515: VecGetArray(v, &array);
4516: /* Get values */
4517: if (numFields > 0) {
4518: PetscInt offset = 0, f;
4519: for (f = 0; f < numFields; ++f) {
4520: const PetscInt **perms = NULL;
4521: const PetscScalar **flips = NULL;
4523: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4524: switch (mode) {
4525: case INSERT_VALUES:
4526: for (p = 0; p < numPoints; p++) {
4527: const PetscInt point = points[2*p];
4528: const PetscInt *perm = perms ? perms[p] : NULL;
4529: const PetscScalar *flip = flips ? flips[p] : NULL;
4530: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4531: } break;
4532: case INSERT_ALL_VALUES:
4533: for (p = 0; p < numPoints; p++) {
4534: const PetscInt point = points[2*p];
4535: const PetscInt *perm = perms ? perms[p] : NULL;
4536: const PetscScalar *flip = flips ? flips[p] : NULL;
4537: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4538: } break;
4539: case INSERT_BC_VALUES:
4540: for (p = 0; p < numPoints; p++) {
4541: const PetscInt point = points[2*p];
4542: const PetscInt *perm = perms ? perms[p] : NULL;
4543: const PetscScalar *flip = flips ? flips[p] : NULL;
4544: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4545: } break;
4546: case ADD_VALUES:
4547: for (p = 0; p < numPoints; p++) {
4548: const PetscInt point = points[2*p];
4549: const PetscInt *perm = perms ? perms[p] : NULL;
4550: const PetscScalar *flip = flips ? flips[p] : NULL;
4551: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4552: } break;
4553: case ADD_ALL_VALUES:
4554: for (p = 0; p < numPoints; p++) {
4555: const PetscInt point = points[2*p];
4556: const PetscInt *perm = perms ? perms[p] : NULL;
4557: const PetscScalar *flip = flips ? flips[p] : NULL;
4558: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4559: } break;
4560: case ADD_BC_VALUES:
4561: for (p = 0; p < numPoints; p++) {
4562: const PetscInt point = points[2*p];
4563: const PetscInt *perm = perms ? perms[p] : NULL;
4564: const PetscScalar *flip = flips ? flips[p] : NULL;
4565: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4566: } break;
4567: default:
4568: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4569: }
4570: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4571: }
4572: } else {
4573: PetscInt dof, off;
4574: const PetscInt **perms = NULL;
4575: const PetscScalar **flips = NULL;
4577: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4578: switch (mode) {
4579: case INSERT_VALUES:
4580: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4581: const PetscInt point = points[2*p];
4582: const PetscInt *perm = perms ? perms[p] : NULL;
4583: const PetscScalar *flip = flips ? flips[p] : NULL;
4584: PetscSectionGetDof(section, point, &dof);
4585: updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4586: } break;
4587: case INSERT_ALL_VALUES:
4588: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4589: const PetscInt point = points[2*p];
4590: const PetscInt *perm = perms ? perms[p] : NULL;
4591: const PetscScalar *flip = flips ? flips[p] : NULL;
4592: PetscSectionGetDof(section, point, &dof);
4593: updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array);
4594: } break;
4595: case INSERT_BC_VALUES:
4596: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4597: const PetscInt point = points[2*p];
4598: const PetscInt *perm = perms ? perms[p] : NULL;
4599: const PetscScalar *flip = flips ? flips[p] : NULL;
4600: PetscSectionGetDof(section, point, &dof);
4601: updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array);
4602: } break;
4603: case ADD_VALUES:
4604: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4605: const PetscInt point = points[2*p];
4606: const PetscInt *perm = perms ? perms[p] : NULL;
4607: const PetscScalar *flip = flips ? flips[p] : NULL;
4608: PetscSectionGetDof(section, point, &dof);
4609: updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array);
4610: } break;
4611: case ADD_ALL_VALUES:
4612: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4613: const PetscInt point = points[2*p];
4614: const PetscInt *perm = perms ? perms[p] : NULL;
4615: const PetscScalar *flip = flips ? flips[p] : NULL;
4616: PetscSectionGetDof(section, point, &dof);
4617: updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array);
4618: } break;
4619: case ADD_BC_VALUES:
4620: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4621: const PetscInt point = points[2*p];
4622: const PetscInt *perm = perms ? perms[p] : NULL;
4623: const PetscScalar *flip = flips ? flips[p] : NULL;
4624: PetscSectionGetDof(section, point, &dof);
4625: updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array);
4626: } break;
4627: default:
4628: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4629: }
4630: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4631: }
4632: /* Cleanup points */
4633: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4634: /* Cleanup array */
4635: VecRestoreArray(v, &array);
4636: return(0);
4637: }
4639: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4640: {
4641: PetscSection clSection;
4642: IS clPoints;
4643: PetscScalar *array;
4644: PetscInt *points = NULL;
4645: const PetscInt *clp, *clperm;
4646: PetscInt numFields, numPoints, p;
4647: PetscInt offset = 0, f;
4648: PetscErrorCode ierr;
4652: if (!section) {DMGetSection(dm, §ion);}
4655: PetscSectionGetNumFields(section, &numFields);
4656: /* Get points */
4657: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4658: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4659: /* Get array */
4660: VecGetArray(v, &array);
4661: /* Get values */
4662: for (f = 0; f < numFields; ++f) {
4663: const PetscInt **perms = NULL;
4664: const PetscScalar **flips = NULL;
4666: if (!fieldActive[f]) {
4667: for (p = 0; p < numPoints*2; p += 2) {
4668: PetscInt fdof;
4669: PetscSectionGetFieldDof(section, points[p], f, &fdof);
4670: offset += fdof;
4671: }
4672: continue;
4673: }
4674: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4675: switch (mode) {
4676: case INSERT_VALUES:
4677: for (p = 0; p < numPoints; p++) {
4678: const PetscInt point = points[2*p];
4679: const PetscInt *perm = perms ? perms[p] : NULL;
4680: const PetscScalar *flip = flips ? flips[p] : NULL;
4681: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4682: } break;
4683: case INSERT_ALL_VALUES:
4684: for (p = 0; p < numPoints; p++) {
4685: const PetscInt point = points[2*p];
4686: const PetscInt *perm = perms ? perms[p] : NULL;
4687: const PetscScalar *flip = flips ? flips[p] : NULL;
4688: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4689: } break;
4690: case INSERT_BC_VALUES:
4691: for (p = 0; p < numPoints; p++) {
4692: const PetscInt point = points[2*p];
4693: const PetscInt *perm = perms ? perms[p] : NULL;
4694: const PetscScalar *flip = flips ? flips[p] : NULL;
4695: updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4696: } break;
4697: case ADD_VALUES:
4698: for (p = 0; p < numPoints; p++) {
4699: const PetscInt point = points[2*p];
4700: const PetscInt *perm = perms ? perms[p] : NULL;
4701: const PetscScalar *flip = flips ? flips[p] : NULL;
4702: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4703: } break;
4704: case ADD_ALL_VALUES:
4705: for (p = 0; p < numPoints; p++) {
4706: const PetscInt point = points[2*p];
4707: const PetscInt *perm = perms ? perms[p] : NULL;
4708: const PetscScalar *flip = flips ? flips[p] : NULL;
4709: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4710: } break;
4711: default:
4712: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4713: }
4714: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4715: }
4716: /* Cleanup points */
4717: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4718: /* Cleanup array */
4719: VecRestoreArray(v, &array);
4720: return(0);
4721: }
4723: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4724: {
4725: PetscMPIInt rank;
4726: PetscInt i, j;
4730: MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4731: PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4732: for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4733: for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4734: numCIndices = numCIndices ? numCIndices : numRIndices;
4735: for (i = 0; i < numRIndices; i++) {
4736: PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4737: for (j = 0; j < numCIndices; j++) {
4738: #if defined(PETSC_USE_COMPLEX)
4739: PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4740: #else
4741: PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4742: #endif
4743: }
4744: PetscViewerASCIIPrintf(viewer, "\n");
4745: }
4746: return(0);
4747: }
4749: /* . off - The global offset of this point */
4750: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4751: {
4752: PetscInt dof; /* The number of unknowns on this point */
4753: PetscInt cdof; /* The number of constraints on this point */
4754: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4755: PetscInt cind = 0, k;
4756: PetscErrorCode ierr;
4759: PetscSectionGetDof(section, point, &dof);
4760: PetscSectionGetConstraintDof(section, point, &cdof);
4761: if (!cdof || setBC) {
4762: if (perm) {
4763: for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4764: } else {
4765: for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4766: }
4767: } else {
4768: PetscSectionGetConstraintIndices(section, point, &cdofs);
4769: if (perm) {
4770: for (k = 0; k < dof; ++k) {
4771: if ((cind < cdof) && (k == cdofs[cind])) {
4772: /* Insert check for returning constrained indices */
4773: indices[*loff+perm[k]] = -(off+k+1);
4774: ++cind;
4775: } else {
4776: indices[*loff+perm[k]] = off+k-cind;
4777: }
4778: }
4779: } else {
4780: for (k = 0; k < dof; ++k) {
4781: if ((cind < cdof) && (k == cdofs[cind])) {
4782: /* Insert check for returning constrained indices */
4783: indices[*loff+k] = -(off+k+1);
4784: ++cind;
4785: } else {
4786: indices[*loff+k] = off+k-cind;
4787: }
4788: }
4789: }
4790: }
4791: *loff += dof;
4792: return(0);
4793: }
4795: /*
4796: This version only believes the point offset from the globalSection
4798: . off - The global offset of this point
4799: */
4800: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4801: {
4802: PetscInt numFields, foff, f;
4806: PetscSectionGetNumFields(section, &numFields);
4807: for (f = 0, foff = 0; f < numFields; ++f) {
4808: PetscInt fdof, cfdof;
4809: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4810: PetscInt cind = 0, b;
4811: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4813: PetscSectionGetFieldDof(section, point, f, &fdof);
4814: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4815: if (!cfdof || setBC) {
4816: if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4817: else {for (b = 0; b < fdof; b++) {indices[foffs[f]+ b ] = off+foff+b;}}
4818: } else {
4819: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4820: if (perm) {
4821: for (b = 0; b < fdof; b++) {
4822: if ((cind < cfdof) && (b == fcdofs[cind])) {
4823: indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4824: ++cind;
4825: } else {
4826: indices[foffs[f]+perm[b]] = off+foff+b-cind;
4827: }
4828: }
4829: } else {
4830: for (b = 0; b < fdof; b++) {
4831: if ((cind < cfdof) && (b == fcdofs[cind])) {
4832: indices[foffs[f]+b] = -(off+foff+b+1);
4833: ++cind;
4834: } else {
4835: indices[foffs[f]+b] = off+foff+b-cind;
4836: }
4837: }
4838: }
4839: }
4840: foff += (setBC ? fdof : (fdof - cfdof));
4841: foffs[f] += fdof;
4842: }
4843: return(0);
4844: }
4846: /*
4847: This version believes the globalSection offsets for each field, rather than just the point offset
4849: . foffs - The offset into 'indices' for each field, since it is segregated by field
4850: */
4851: PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4852: {
4853: PetscInt numFields, foff, f;
4857: PetscSectionGetNumFields(section, &numFields);
4858: for (f = 0; f < numFields; ++f) {
4859: PetscInt fdof, cfdof;
4860: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4861: PetscInt cind = 0, b;
4862: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4864: PetscSectionGetFieldDof(section, point, f, &fdof);
4865: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4866: PetscSectionGetFieldOffset(globalSection, point, f, &foff);
4867: if (!cfdof || setBC) {
4868: if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = foff+b;}}
4869: else {for (b = 0; b < fdof; b++) {indices[foffs[f]+ b ] = foff+b;}}
4870: } else {
4871: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4872: if (perm) {
4873: for (b = 0; b < fdof; b++) {
4874: if ((cind < cfdof) && (b == fcdofs[cind])) {
4875: indices[foffs[f]+perm[b]] = -(foff+b+1);
4876: ++cind;
4877: } else {
4878: indices[foffs[f]+perm[b]] = foff+b-cind;
4879: }
4880: }
4881: } else {
4882: for (b = 0; b < fdof; b++) {
4883: if ((cind < cfdof) && (b == fcdofs[cind])) {
4884: indices[foffs[f]+b] = -(foff+b+1);
4885: ++cind;
4886: } else {
4887: indices[foffs[f]+b] = foff+b-cind;
4888: }
4889: }
4890: }
4891: }
4892: foffs[f] += fdof;
4893: }
4894: return(0);
4895: }
4897: 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)
4898: {
4899: Mat cMat;
4900: PetscSection aSec, cSec;
4901: IS aIS;
4902: PetscInt aStart = -1, aEnd = -1;
4903: const PetscInt *anchors;
4904: PetscInt numFields, f, p, q, newP = 0;
4905: PetscInt newNumPoints = 0, newNumIndices = 0;
4906: PetscInt *newPoints, *indices, *newIndices;
4907: PetscInt maxAnchor, maxDof;
4908: PetscInt newOffsets[32];
4909: PetscInt *pointMatOffsets[32];
4910: PetscInt *newPointOffsets[32];
4911: PetscScalar *pointMat[32];
4912: PetscScalar *newValues=NULL,*tmpValues;
4913: PetscBool anyConstrained = PETSC_FALSE;
4914: PetscErrorCode ierr;
4919: PetscSectionGetNumFields(section, &numFields);
4921: DMPlexGetAnchors(dm,&aSec,&aIS);
4922: /* if there are point-to-point constraints */
4923: if (aSec) {
4924: PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4925: ISGetIndices(aIS,&anchors);
4926: PetscSectionGetChart(aSec,&aStart,&aEnd);
4927: /* figure out how many points are going to be in the new element matrix
4928: * (we allow double counting, because it's all just going to be summed
4929: * into the global matrix anyway) */
4930: for (p = 0; p < 2*numPoints; p+=2) {
4931: PetscInt b = points[p];
4932: PetscInt bDof = 0, bSecDof;
4934: PetscSectionGetDof(section,b,&bSecDof);
4935: if (!bSecDof) {
4936: continue;
4937: }
4938: if (b >= aStart && b < aEnd) {
4939: PetscSectionGetDof(aSec,b,&bDof);
4940: }
4941: if (bDof) {
4942: /* this point is constrained */
4943: /* it is going to be replaced by its anchors */
4944: PetscInt bOff, q;
4946: anyConstrained = PETSC_TRUE;
4947: newNumPoints += bDof;
4948: PetscSectionGetOffset(aSec,b,&bOff);
4949: for (q = 0; q < bDof; q++) {
4950: PetscInt a = anchors[bOff + q];
4951: PetscInt aDof;
4953: PetscSectionGetDof(section,a,&aDof);
4954: newNumIndices += aDof;
4955: for (f = 0; f < numFields; ++f) {
4956: PetscInt fDof;
4958: PetscSectionGetFieldDof(section, a, f, &fDof);
4959: newOffsets[f+1] += fDof;
4960: }
4961: }
4962: }
4963: else {
4964: /* this point is not constrained */
4965: newNumPoints++;
4966: newNumIndices += bSecDof;
4967: for (f = 0; f < numFields; ++f) {
4968: PetscInt fDof;
4970: PetscSectionGetFieldDof(section, b, f, &fDof);
4971: newOffsets[f+1] += fDof;
4972: }
4973: }
4974: }
4975: }
4976: if (!anyConstrained) {
4977: if (outNumPoints) *outNumPoints = 0;
4978: if (outNumIndices) *outNumIndices = 0;
4979: if (outPoints) *outPoints = NULL;
4980: if (outValues) *outValues = NULL;
4981: if (aSec) {ISRestoreIndices(aIS,&anchors);}
4982: return(0);
4983: }
4985: if (outNumPoints) *outNumPoints = newNumPoints;
4986: if (outNumIndices) *outNumIndices = newNumIndices;
4988: for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
4990: if (!outPoints && !outValues) {
4991: if (offsets) {
4992: for (f = 0; f <= numFields; f++) {
4993: offsets[f] = newOffsets[f];
4994: }
4995: }
4996: if (aSec) {ISRestoreIndices(aIS,&anchors);}
4997: return(0);
4998: }
5000: if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
5002: DMGetDefaultConstraints(dm, &cSec, &cMat);
5004: /* workspaces */
5005: if (numFields) {
5006: for (f = 0; f < numFields; f++) {
5007: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5008: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5009: }
5010: }
5011: else {
5012: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5013: DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5014: }
5016: /* get workspaces for the point-to-point matrices */
5017: if (numFields) {
5018: PetscInt totalOffset, totalMatOffset;
5020: for (p = 0; p < numPoints; p++) {
5021: PetscInt b = points[2*p];
5022: PetscInt bDof = 0, bSecDof;
5024: PetscSectionGetDof(section,b,&bSecDof);
5025: if (!bSecDof) {
5026: for (f = 0; f < numFields; f++) {
5027: newPointOffsets[f][p + 1] = 0;
5028: pointMatOffsets[f][p + 1] = 0;
5029: }
5030: continue;
5031: }
5032: if (b >= aStart && b < aEnd) {
5033: PetscSectionGetDof(aSec, b, &bDof);
5034: }
5035: if (bDof) {
5036: for (f = 0; f < numFields; f++) {
5037: PetscInt fDof, q, bOff, allFDof = 0;
5039: PetscSectionGetFieldDof(section, b, f, &fDof);
5040: PetscSectionGetOffset(aSec, b, &bOff);
5041: for (q = 0; q < bDof; q++) {
5042: PetscInt a = anchors[bOff + q];
5043: PetscInt aFDof;
5045: PetscSectionGetFieldDof(section, a, f, &aFDof);
5046: allFDof += aFDof;
5047: }
5048: newPointOffsets[f][p+1] = allFDof;
5049: pointMatOffsets[f][p+1] = fDof * allFDof;
5050: }
5051: }
5052: else {
5053: for (f = 0; f < numFields; f++) {
5054: PetscInt fDof;
5056: PetscSectionGetFieldDof(section, b, f, &fDof);
5057: newPointOffsets[f][p+1] = fDof;
5058: pointMatOffsets[f][p+1] = 0;
5059: }
5060: }
5061: }
5062: for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5063: newPointOffsets[f][0] = totalOffset;
5064: pointMatOffsets[f][0] = totalMatOffset;
5065: for (p = 0; p < numPoints; p++) {
5066: newPointOffsets[f][p+1] += newPointOffsets[f][p];
5067: pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5068: }
5069: totalOffset = newPointOffsets[f][numPoints];
5070: totalMatOffset = pointMatOffsets[f][numPoints];
5071: DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5072: }
5073: }
5074: else {
5075: for (p = 0; p < numPoints; p++) {
5076: PetscInt b = points[2*p];
5077: PetscInt bDof = 0, bSecDof;
5079: PetscSectionGetDof(section,b,&bSecDof);
5080: if (!bSecDof) {
5081: newPointOffsets[0][p + 1] = 0;
5082: pointMatOffsets[0][p + 1] = 0;
5083: continue;
5084: }
5085: if (b >= aStart && b < aEnd) {
5086: PetscSectionGetDof(aSec, b, &bDof);
5087: }
5088: if (bDof) {
5089: PetscInt bOff, q, allDof = 0;
5091: PetscSectionGetOffset(aSec, b, &bOff);
5092: for (q = 0; q < bDof; q++) {
5093: PetscInt a = anchors[bOff + q], aDof;
5095: PetscSectionGetDof(section, a, &aDof);
5096: allDof += aDof;
5097: }
5098: newPointOffsets[0][p+1] = allDof;
5099: pointMatOffsets[0][p+1] = bSecDof * allDof;
5100: }
5101: else {
5102: newPointOffsets[0][p+1] = bSecDof;
5103: pointMatOffsets[0][p+1] = 0;
5104: }
5105: }
5106: newPointOffsets[0][0] = 0;
5107: pointMatOffsets[0][0] = 0;
5108: for (p = 0; p < numPoints; p++) {
5109: newPointOffsets[0][p+1] += newPointOffsets[0][p];
5110: pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5111: }
5112: DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5113: }
5115: /* output arrays */
5116: DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5118: /* get the point-to-point matrices; construct newPoints */
5119: PetscSectionGetMaxDof(aSec, &maxAnchor);
5120: PetscSectionGetMaxDof(section, &maxDof);
5121: DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5122: DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5123: if (numFields) {
5124: for (p = 0, newP = 0; p < numPoints; p++) {
5125: PetscInt b = points[2*p];
5126: PetscInt o = points[2*p+1];
5127: PetscInt bDof = 0, bSecDof;
5129: PetscSectionGetDof(section, b, &bSecDof);
5130: if (!bSecDof) {
5131: continue;
5132: }
5133: if (b >= aStart && b < aEnd) {
5134: PetscSectionGetDof(aSec, b, &bDof);
5135: }
5136: if (bDof) {
5137: PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5139: fStart[0] = 0;
5140: fEnd[0] = 0;
5141: for (f = 0; f < numFields; f++) {
5142: PetscInt fDof;
5144: PetscSectionGetFieldDof(cSec, b, f, &fDof);
5145: fStart[f+1] = fStart[f] + fDof;
5146: fEnd[f+1] = fStart[f+1];
5147: }
5148: PetscSectionGetOffset(cSec, b, &bOff);
5149: DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);
5151: fAnchorStart[0] = 0;
5152: fAnchorEnd[0] = 0;
5153: for (f = 0; f < numFields; f++) {
5154: PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5156: fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5157: fAnchorEnd[f+1] = fAnchorStart[f + 1];
5158: }
5159: PetscSectionGetOffset(aSec, b, &bOff);
5160: for (q = 0; q < bDof; q++) {
5161: PetscInt a = anchors[bOff + q], aOff;
5163: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5164: newPoints[2*(newP + q)] = a;
5165: newPoints[2*(newP + q) + 1] = 0;
5166: PetscSectionGetOffset(section, a, &aOff);
5167: DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5168: }
5169: newP += bDof;
5171: if (outValues) {
5172: /* get the point-to-point submatrix */
5173: for (f = 0; f < numFields; f++) {
5174: MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5175: }
5176: }
5177: }
5178: else {
5179: newPoints[2 * newP] = b;
5180: newPoints[2 * newP + 1] = o;
5181: newP++;
5182: }
5183: }
5184: } else {
5185: for (p = 0; p < numPoints; p++) {
5186: PetscInt b = points[2*p];
5187: PetscInt o = points[2*p+1];
5188: PetscInt bDof = 0, bSecDof;
5190: PetscSectionGetDof(section, b, &bSecDof);
5191: if (!bSecDof) {
5192: continue;
5193: }
5194: if (b >= aStart && b < aEnd) {
5195: PetscSectionGetDof(aSec, b, &bDof);
5196: }
5197: if (bDof) {
5198: PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5200: PetscSectionGetOffset(cSec, b, &bOff);
5201: DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);
5203: PetscSectionGetOffset (aSec, b, &bOff);
5204: for (q = 0; q < bDof; q++) {
5205: PetscInt a = anchors[bOff + q], aOff;
5207: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5209: newPoints[2*(newP + q)] = a;
5210: newPoints[2*(newP + q) + 1] = 0;
5211: PetscSectionGetOffset(section, a, &aOff);
5212: DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5213: }
5214: newP += bDof;
5216: /* get the point-to-point submatrix */
5217: if (outValues) {
5218: MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5219: }
5220: }
5221: else {
5222: newPoints[2 * newP] = b;
5223: newPoints[2 * newP + 1] = o;
5224: newP++;
5225: }
5226: }
5227: }
5229: if (outValues) {
5230: DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5231: PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5232: /* multiply constraints on the right */
5233: if (numFields) {
5234: for (f = 0; f < numFields; f++) {
5235: PetscInt oldOff = offsets[f];
5237: for (p = 0; p < numPoints; p++) {
5238: PetscInt cStart = newPointOffsets[f][p];
5239: PetscInt b = points[2 * p];
5240: PetscInt c, r, k;
5241: PetscInt dof;
5243: PetscSectionGetFieldDof(section,b,f,&dof);
5244: if (!dof) {
5245: continue;
5246: }
5247: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5248: PetscInt nCols = newPointOffsets[f][p+1]-cStart;
5249: const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5251: for (r = 0; r < numIndices; r++) {
5252: for (c = 0; c < nCols; c++) {
5253: for (k = 0; k < dof; k++) {
5254: tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5255: }
5256: }
5257: }
5258: }
5259: else {
5260: /* copy this column as is */
5261: for (r = 0; r < numIndices; r++) {
5262: for (c = 0; c < dof; c++) {
5263: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5264: }
5265: }
5266: }
5267: oldOff += dof;
5268: }
5269: }
5270: }
5271: else {
5272: PetscInt oldOff = 0;
5273: for (p = 0; p < numPoints; p++) {
5274: PetscInt cStart = newPointOffsets[0][p];
5275: PetscInt b = points[2 * p];
5276: PetscInt c, r, k;
5277: PetscInt dof;
5279: PetscSectionGetDof(section,b,&dof);
5280: if (!dof) {
5281: continue;
5282: }
5283: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5284: PetscInt nCols = newPointOffsets[0][p+1]-cStart;
5285: const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5287: for (r = 0; r < numIndices; r++) {
5288: for (c = 0; c < nCols; c++) {
5289: for (k = 0; k < dof; k++) {
5290: tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5291: }
5292: }
5293: }
5294: }
5295: else {
5296: /* copy this column as is */
5297: for (r = 0; r < numIndices; r++) {
5298: for (c = 0; c < dof; c++) {
5299: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5300: }
5301: }
5302: }
5303: oldOff += dof;
5304: }
5305: }
5307: if (multiplyLeft) {
5308: DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5309: PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5310: /* multiply constraints transpose on the left */
5311: if (numFields) {
5312: for (f = 0; f < numFields; f++) {
5313: PetscInt oldOff = offsets[f];
5315: for (p = 0; p < numPoints; p++) {
5316: PetscInt rStart = newPointOffsets[f][p];
5317: PetscInt b = points[2 * p];
5318: PetscInt c, r, k;
5319: PetscInt dof;
5321: PetscSectionGetFieldDof(section,b,f,&dof);
5322: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5323: PetscInt nRows = newPointOffsets[f][p+1]-rStart;
5324: const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5326: for (r = 0; r < nRows; r++) {
5327: for (c = 0; c < newNumIndices; c++) {
5328: for (k = 0; k < dof; k++) {
5329: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5330: }
5331: }
5332: }
5333: }
5334: else {
5335: /* copy this row as is */
5336: for (r = 0; r < dof; r++) {
5337: for (c = 0; c < newNumIndices; c++) {
5338: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5339: }
5340: }
5341: }
5342: oldOff += dof;
5343: }
5344: }
5345: }
5346: else {
5347: PetscInt oldOff = 0;
5349: for (p = 0; p < numPoints; p++) {
5350: PetscInt rStart = newPointOffsets[0][p];
5351: PetscInt b = points[2 * p];
5352: PetscInt c, r, k;
5353: PetscInt dof;
5355: PetscSectionGetDof(section,b,&dof);
5356: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5357: PetscInt nRows = newPointOffsets[0][p+1]-rStart;
5358: const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5360: for (r = 0; r < nRows; r++) {
5361: for (c = 0; c < newNumIndices; c++) {
5362: for (k = 0; k < dof; k++) {
5363: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5364: }
5365: }
5366: }
5367: }
5368: else {
5369: /* copy this row as is */
5370: for (r = 0; r < dof; r++) {
5371: for (c = 0; c < newNumIndices; c++) {
5372: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5373: }
5374: }
5375: }
5376: oldOff += dof;
5377: }
5378: }
5380: DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5381: }
5382: else {
5383: newValues = tmpValues;
5384: }
5385: }
5387: /* clean up */
5388: DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5389: DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5391: if (numFields) {
5392: for (f = 0; f < numFields; f++) {
5393: DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5394: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5395: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5396: }
5397: }
5398: else {
5399: DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5400: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5401: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5402: }
5403: ISRestoreIndices(aIS,&anchors);
5405: /* output */
5406: if (outPoints) {
5407: *outPoints = newPoints;
5408: }
5409: else {
5410: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5411: }
5412: if (outValues) {
5413: *outValues = newValues;
5414: }
5415: for (f = 0; f <= numFields; f++) {
5416: offsets[f] = newOffsets[f];
5417: }
5418: return(0);
5419: }
5421: /*@C
5422: DMPlexGetClosureIndices - Get the global indices in a vector v for all points in the closure of the given point
5424: Not collective
5426: Input Parameters:
5427: + dm - The DM
5428: . section - The section describing the layout in v, or NULL to use the default section
5429: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5430: - point - The mesh point
5432: Output parameters:
5433: + numIndices - The number of indices
5434: . indices - The indices
5435: - outOffsets - Field offset if not NULL
5437: Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5439: Level: advanced
5441: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5442: @*/
5443: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5444: {
5445: PetscSection clSection;
5446: IS clPoints;
5447: const PetscInt *clp;
5448: const PetscInt **perms[32] = {NULL};
5449: PetscInt *points = NULL, *pointsNew;
5450: PetscInt numPoints, numPointsNew;
5451: PetscInt offsets[32];
5452: PetscInt Nf, Nind, NindNew, off, globalOff, f, p;
5453: PetscErrorCode ierr;
5461: PetscSectionGetNumFields(section, &Nf);
5462: if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5463: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5464: /* Get points in closure */
5465: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5466: /* Get number of indices and indices per field */
5467: for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5468: PetscInt dof, fdof;
5470: PetscSectionGetDof(section, points[p], &dof);
5471: for (f = 0; f < Nf; ++f) {
5472: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5473: offsets[f+1] += fdof;
5474: }
5475: Nind += dof;
5476: }
5477: for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5478: if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5479: if (!Nf) offsets[1] = Nind;
5480: /* Get dual space symmetries */
5481: for (f = 0; f < PetscMax(1,Nf); f++) {
5482: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5483: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5484: }
5485: /* Correct for hanging node constraints */
5486: {
5487: DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5488: if (numPointsNew) {
5489: for (f = 0; f < PetscMax(1,Nf); f++) {
5490: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5491: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5492: }
5493: for (f = 0; f < PetscMax(1,Nf); f++) {
5494: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5495: else {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5496: }
5497: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5498: numPoints = numPointsNew;
5499: Nind = NindNew;
5500: points = pointsNew;
5501: }
5502: }
5503: /* Calculate indices */
5504: DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5505: if (Nf) {
5506: if (outOffsets) {
5507: PetscInt f;
5509: for (f = 0; f <= Nf; f++) {
5510: outOffsets[f] = offsets[f];
5511: }
5512: }
5513: for (p = 0; p < numPoints; p++) {
5514: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5515: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5516: }
5517: } else {
5518: for (p = 0, off = 0; p < numPoints; p++) {
5519: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5521: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5522: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5523: }
5524: }
5525: /* Cleanup points */
5526: for (f = 0; f < PetscMax(1,Nf); f++) {
5527: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5528: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5529: }
5530: if (numPointsNew) {
5531: DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5532: } else {
5533: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5534: }
5535: if (numIndices) *numIndices = Nind;
5536: return(0);
5537: }
5539: /*@C
5540: DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5542: Not collective
5544: Input Parameters:
5545: + dm - The DM
5546: . section - The section describing the layout in v, or NULL to use the default section
5547: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5548: . point - The mesh point
5549: . numIndices - The number of indices
5550: . indices - The indices
5551: - outOffsets - Field offset if not NULL
5553: Level: advanced
5555: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5556: @*/
5557: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5558: {
5564: DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5565: return(0);
5566: }
5568: /*@C
5569: DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5571: Not collective
5573: Input Parameters:
5574: + dm - The DM
5575: . section - The section describing the layout in v, or NULL to use the default section
5576: . globalSection - The section describing the layout in v, or NULL to use the default global section
5577: . A - The matrix
5578: . point - The point in the DM
5579: . values - The array of values
5580: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5582: Fortran Notes:
5583: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5585: Level: intermediate
5587: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5588: @*/
5589: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5590: {
5591: DM_Plex *mesh = (DM_Plex*) dm->data;
5592: PetscSection clSection;
5593: IS clPoints;
5594: PetscInt *points = NULL, *newPoints;
5595: const PetscInt *clp;
5596: PetscInt *indices;
5597: PetscInt offsets[32];
5598: const PetscInt **perms[32] = {NULL};
5599: const PetscScalar **flips[32] = {NULL};
5600: PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5601: PetscScalar *valCopy = NULL;
5602: PetscScalar *newValues;
5603: PetscErrorCode ierr;
5607: if (!section) {DMGetSection(dm, §ion);}
5609: if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5612: PetscSectionGetNumFields(section, &numFields);
5613: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5614: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5615: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5616: for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5617: PetscInt fdof;
5619: PetscSectionGetDof(section, points[p], &dof);
5620: for (f = 0; f < numFields; ++f) {
5621: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5622: offsets[f+1] += fdof;
5623: }
5624: numIndices += dof;
5625: }
5626: for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5628: if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5629: /* Get symmetries */
5630: for (f = 0; f < PetscMax(1,numFields); f++) {
5631: if (numFields) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5632: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5633: if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5634: PetscInt foffset = offsets[f];
5636: for (p = 0; p < numPoints; p++) {
5637: PetscInt point = points[2*p], fdof;
5638: const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5640: if (!numFields) {
5641: PetscSectionGetDof(section,point,&fdof);
5642: } else {
5643: PetscSectionGetFieldDof(section,point,f,&fdof);
5644: }
5645: if (flip) {
5646: PetscInt i, j, k;
5648: if (!valCopy) {
5649: DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5650: for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5651: values = valCopy;
5652: }
5653: for (i = 0; i < fdof; i++) {
5654: PetscScalar fval = flip[i];
5656: for (k = 0; k < numIndices; k++) {
5657: valCopy[numIndices * (foffset + i) + k] *= fval;
5658: valCopy[numIndices * k + (foffset + i)] *= fval;
5659: }
5660: }
5661: }
5662: foffset += fdof;
5663: }
5664: }
5665: }
5666: DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5667: if (newNumPoints) {
5668: if (valCopy) {
5669: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5670: }
5671: for (f = 0; f < PetscMax(1,numFields); f++) {
5672: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5673: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5674: }
5675: for (f = 0; f < PetscMax(1,numFields); f++) {
5676: if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5677: else {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5678: }
5679: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5680: numPoints = newNumPoints;
5681: numIndices = newNumIndices;
5682: points = newPoints;
5683: values = newValues;
5684: }
5685: DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5686: if (numFields) {
5687: PetscBool useFieldOffsets;
5689: PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
5690: if (useFieldOffsets) {
5691: for (p = 0; p < numPoints; p++) {
5692: DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, indices);
5693: }
5694: } else {
5695: for (p = 0; p < numPoints; p++) {
5696: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5697: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5698: }
5699: }
5700: } else {
5701: for (p = 0, off = 0; p < numPoints; p++) {
5702: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5703: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5704: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5705: }
5706: }
5707: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5708: MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5709: if (mesh->printFEM > 1) {
5710: PetscInt i;
5711: PetscPrintf(PETSC_COMM_SELF, " Indices:");
5712: for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5713: PetscPrintf(PETSC_COMM_SELF, "\n");
5714: }
5715: if (ierr) {
5716: PetscMPIInt rank;
5717: PetscErrorCode ierr2;
5719: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5720: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5721: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5722: ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5723:
5724: }
5725: for (f = 0; f < PetscMax(1,numFields); f++) {
5726: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5727: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5728: }
5729: if (newNumPoints) {
5730: DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5731: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5732: }
5733: else {
5734: if (valCopy) {
5735: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5736: }
5737: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5738: }
5739: DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5740: return(0);
5741: }
5743: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5744: {
5745: DM_Plex *mesh = (DM_Plex*) dmf->data;
5746: PetscInt *fpoints = NULL, *ftotpoints = NULL;
5747: PetscInt *cpoints = NULL;
5748: PetscInt *findices, *cindices;
5749: PetscInt foffsets[32], coffsets[32];
5750: CellRefiner cellRefiner;
5751: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5752: PetscErrorCode ierr;
5757: if (!fsection) {DMGetSection(dmf, &fsection);}
5759: if (!csection) {DMGetSection(dmc, &csection);}
5761: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
5763: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
5766: PetscSectionGetNumFields(fsection, &numFields);
5767: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5768: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5769: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5770: /* Column indices */
5771: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5772: maxFPoints = numCPoints;
5773: /* Compress out points not in the section */
5774: /* TODO: Squeeze out points with 0 dof as well */
5775: PetscSectionGetChart(csection, &pStart, &pEnd);
5776: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5777: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5778: cpoints[q*2] = cpoints[p];
5779: cpoints[q*2+1] = cpoints[p+1];
5780: ++q;
5781: }
5782: }
5783: numCPoints = q;
5784: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5785: PetscInt fdof;
5787: PetscSectionGetDof(csection, cpoints[p], &dof);
5788: if (!dof) continue;
5789: for (f = 0; f < numFields; ++f) {
5790: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5791: coffsets[f+1] += fdof;
5792: }
5793: numCIndices += dof;
5794: }
5795: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5796: /* Row indices */
5797: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5798: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5799: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5800: for (r = 0, q = 0; r < numSubcells; ++r) {
5801: /* TODO Map from coarse to fine cells */
5802: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5803: /* Compress out points not in the section */
5804: PetscSectionGetChart(fsection, &pStart, &pEnd);
5805: for (p = 0; p < numFPoints*2; p += 2) {
5806: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5807: PetscSectionGetDof(fsection, fpoints[p], &dof);
5808: if (!dof) continue;
5809: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5810: if (s < q) continue;
5811: ftotpoints[q*2] = fpoints[p];
5812: ftotpoints[q*2+1] = fpoints[p+1];
5813: ++q;
5814: }
5815: }
5816: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5817: }
5818: numFPoints = q;
5819: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5820: PetscInt fdof;
5822: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5823: if (!dof) continue;
5824: for (f = 0; f < numFields; ++f) {
5825: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5826: foffsets[f+1] += fdof;
5827: }
5828: numFIndices += dof;
5829: }
5830: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5832: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5833: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5834: DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5835: DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5836: if (numFields) {
5837: const PetscInt **permsF[32] = {NULL};
5838: const PetscInt **permsC[32] = {NULL};
5840: for (f = 0; f < numFields; f++) {
5841: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5842: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5843: }
5844: for (p = 0; p < numFPoints; p++) {
5845: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5846: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5847: }
5848: for (p = 0; p < numCPoints; p++) {
5849: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5850: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5851: }
5852: for (f = 0; f < numFields; f++) {
5853: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5854: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5855: }
5856: } else {
5857: const PetscInt **permsF = NULL;
5858: const PetscInt **permsC = NULL;
5860: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5861: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5862: for (p = 0, off = 0; p < numFPoints; p++) {
5863: const PetscInt *perm = permsF ? permsF[p] : NULL;
5865: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5866: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5867: }
5868: for (p = 0, off = 0; p < numCPoints; p++) {
5869: const PetscInt *perm = permsC ? permsC[p] : NULL;
5871: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5872: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5873: }
5874: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5875: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5876: }
5877: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5878: /* TODO: flips */
5879: MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5880: if (ierr) {
5881: PetscMPIInt rank;
5882: PetscErrorCode ierr2;
5884: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5885: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5886: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5887: ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
5888: ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
5889:
5890: }
5891: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
5892: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5893: DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5894: DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5895: return(0);
5896: }
5898: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5899: {
5900: PetscInt *fpoints = NULL, *ftotpoints = NULL;
5901: PetscInt *cpoints = NULL;
5902: PetscInt foffsets[32], coffsets[32];
5903: CellRefiner cellRefiner;
5904: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5910: if (!fsection) {DMGetSection(dmf, &fsection);}
5912: if (!csection) {DMGetSection(dmc, &csection);}
5914: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
5916: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
5918: PetscSectionGetNumFields(fsection, &numFields);
5919: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5920: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5921: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5922: /* Column indices */
5923: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5924: maxFPoints = numCPoints;
5925: /* Compress out points not in the section */
5926: /* TODO: Squeeze out points with 0 dof as well */
5927: PetscSectionGetChart(csection, &pStart, &pEnd);
5928: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5929: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5930: cpoints[q*2] = cpoints[p];
5931: cpoints[q*2+1] = cpoints[p+1];
5932: ++q;
5933: }
5934: }
5935: numCPoints = q;
5936: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5937: PetscInt fdof;
5939: PetscSectionGetDof(csection, cpoints[p], &dof);
5940: if (!dof) continue;
5941: for (f = 0; f < numFields; ++f) {
5942: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5943: coffsets[f+1] += fdof;
5944: }
5945: numCIndices += dof;
5946: }
5947: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5948: /* Row indices */
5949: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5950: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5951: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5952: for (r = 0, q = 0; r < numSubcells; ++r) {
5953: /* TODO Map from coarse to fine cells */
5954: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5955: /* Compress out points not in the section */
5956: PetscSectionGetChart(fsection, &pStart, &pEnd);
5957: for (p = 0; p < numFPoints*2; p += 2) {
5958: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5959: PetscSectionGetDof(fsection, fpoints[p], &dof);
5960: if (!dof) continue;
5961: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5962: if (s < q) continue;
5963: ftotpoints[q*2] = fpoints[p];
5964: ftotpoints[q*2+1] = fpoints[p+1];
5965: ++q;
5966: }
5967: }
5968: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5969: }
5970: numFPoints = q;
5971: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5972: PetscInt fdof;
5974: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5975: if (!dof) continue;
5976: for (f = 0; f < numFields; ++f) {
5977: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5978: foffsets[f+1] += fdof;
5979: }
5980: numFIndices += dof;
5981: }
5982: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5984: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5985: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5986: if (numFields) {
5987: const PetscInt **permsF[32] = {NULL};
5988: const PetscInt **permsC[32] = {NULL};
5990: for (f = 0; f < numFields; f++) {
5991: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5992: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5993: }
5994: for (p = 0; p < numFPoints; p++) {
5995: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5996: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5997: }
5998: for (p = 0; p < numCPoints; p++) {
5999: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6000: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6001: }
6002: for (f = 0; f < numFields; f++) {
6003: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6004: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6005: }
6006: } else {
6007: const PetscInt **permsF = NULL;
6008: const PetscInt **permsC = NULL;
6010: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6011: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6012: for (p = 0, off = 0; p < numFPoints; p++) {
6013: const PetscInt *perm = permsF ? permsF[p] : NULL;
6015: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6016: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6017: }
6018: for (p = 0, off = 0; p < numCPoints; p++) {
6019: const PetscInt *perm = permsC ? permsC[p] : NULL;
6021: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6022: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6023: }
6024: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6025: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6026: }
6027: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6028: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6029: return(0);
6030: }
6032: /*@
6033: DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6035: Input Parameter:
6036: . dm - The DMPlex object
6038: Output Parameters:
6039: + cMax - The first hybrid cell
6040: . fMax - The first hybrid face
6041: . eMax - The first hybrid edge
6042: - vMax - The first hybrid vertex
6044: Level: developer
6046: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6047: @*/
6048: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6049: {
6050: DM_Plex *mesh = (DM_Plex*) dm->data;
6051: PetscInt dim;
6056: DMGetDimension(dm, &dim);
6057: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6058: if (cMax) *cMax = mesh->hybridPointMax[dim];
6059: if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6060: if (eMax) *eMax = mesh->hybridPointMax[1];
6061: if (vMax) *vMax = mesh->hybridPointMax[0];
6062: return(0);
6063: }
6065: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6066: {
6067: IS is, his;
6068: PetscInt first = 0, stride;
6069: PetscBool isStride;
6073: DMLabelGetStratumIS(depthLabel, d, &is);
6074: PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6075: if (isStride) {
6076: ISStrideGetInfo(is, &first, &stride);
6077: }
6078: if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6079: ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6080: DMLabelSetStratumIS(dimLabel, d, his);
6081: ISDestroy(&his);
6082: ISDestroy(&is);
6083: return(0);
6084: }
6086: /*@
6087: DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6089: Input Parameters:
6090: . dm - The DMPlex object
6091: . cMax - The first hybrid cell
6092: . fMax - The first hybrid face
6093: . eMax - The first hybrid edge
6094: - vMax - The first hybrid vertex
6096: Level: developer
6098: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6099: @*/
6100: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6101: {
6102: DM_Plex *mesh = (DM_Plex*) dm->data;
6103: PetscInt dim;
6108: DMGetDimension(dm, &dim);
6109: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6110: if (cMax >= 0) mesh->hybridPointMax[dim] = cMax;
6111: if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6112: if (eMax >= 0) mesh->hybridPointMax[1] = eMax;
6113: if (vMax >= 0) mesh->hybridPointMax[0] = vMax;
6114: return(0);
6115: }
6117: /*@C
6118: DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6120: Input Parameter:
6121: . dm - The DMPlex object
6123: Output Parameter:
6124: . cellHeight - The height of a cell
6126: Level: developer
6128: .seealso DMPlexSetVTKCellHeight()
6129: @*/
6130: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6131: {
6132: DM_Plex *mesh = (DM_Plex*) dm->data;
6137: *cellHeight = mesh->vtkCellHeight;
6138: return(0);
6139: }
6141: /*@C
6142: DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6144: Input Parameters:
6145: + dm - The DMPlex object
6146: - cellHeight - The height of a cell
6148: Level: developer
6150: .seealso DMPlexGetVTKCellHeight()
6151: @*/
6152: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6153: {
6154: DM_Plex *mesh = (DM_Plex*) dm->data;
6158: mesh->vtkCellHeight = cellHeight;
6159: return(0);
6160: }
6162: /* We can easily have a form that takes an IS instead */
6163: PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6164: {
6165: PetscSection section, globalSection;
6166: PetscInt *numbers, p;
6170: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
6171: PetscSectionSetChart(section, pStart, pEnd);
6172: for (p = pStart; p < pEnd; ++p) {
6173: PetscSectionSetDof(section, p, 1);
6174: }
6175: PetscSectionSetUp(section);
6176: PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6177: PetscMalloc1(pEnd - pStart, &numbers);
6178: for (p = pStart; p < pEnd; ++p) {
6179: PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6180: if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6181: else numbers[p-pStart] += shift;
6182: }
6183: ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6184: if (globalSize) {
6185: PetscLayout layout;
6186: PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6187: PetscLayoutGetSize(layout, globalSize);
6188: PetscLayoutDestroy(&layout);
6189: }
6190: PetscSectionDestroy(§ion);
6191: PetscSectionDestroy(&globalSection);
6192: return(0);
6193: }
6195: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6196: {
6197: PetscInt cellHeight, cStart, cEnd, cMax;
6201: DMPlexGetVTKCellHeight(dm, &cellHeight);
6202: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6203: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6204: if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6205: DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6206: return(0);
6207: }
6209: /*@
6210: DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6212: Input Parameter:
6213: . dm - The DMPlex object
6215: Output Parameter:
6216: . globalCellNumbers - Global cell numbers for all cells on this process
6218: Level: developer
6220: .seealso DMPlexGetVertexNumbering()
6221: @*/
6222: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6223: {
6224: DM_Plex *mesh = (DM_Plex*) dm->data;
6229: if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6230: *globalCellNumbers = mesh->globalCellNumbers;
6231: return(0);
6232: }
6234: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6235: {
6236: PetscInt vStart, vEnd, vMax;
6241: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6242: DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6243: if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6244: DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6245: return(0);
6246: }
6248: /*@
6249: DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process
6251: Input Parameter:
6252: . dm - The DMPlex object
6254: Output Parameter:
6255: . globalVertexNumbers - Global vertex numbers for all vertices on this process
6257: Level: developer
6259: .seealso DMPlexGetCellNumbering()
6260: @*/
6261: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6262: {
6263: DM_Plex *mesh = (DM_Plex*) dm->data;
6268: if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6269: *globalVertexNumbers = mesh->globalVertexNumbers;
6270: return(0);
6271: }
6273: /*@
6274: DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6276: Input Parameter:
6277: . dm - The DMPlex object
6279: Output Parameter:
6280: . globalPointNumbers - Global numbers for all points on this process
6282: Level: developer
6284: .seealso DMPlexGetCellNumbering()
6285: @*/
6286: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6287: {
6288: IS nums[4];
6289: PetscInt depths[4], gdepths[4], starts[4];
6290: PetscInt depth, d, shift = 0;
6295: DMPlexGetDepth(dm, &depth);
6296: /* For unstratified meshes use dim instead of depth */
6297: if (depth < 0) {DMGetDimension(dm, &depth);}
6298: for (d = 0; d <= depth; ++d) {
6299: PetscInt end;
6301: depths[d] = depth-d;
6302: DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6303: if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6304: }
6305: PetscSortIntWithArray(depth+1, starts, depths);
6306: MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6307: for (d = 0; d <= depth; ++d) {
6308: if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6309: }
6310: for (d = 0; d <= depth; ++d) {
6311: PetscInt pStart, pEnd, gsize;
6313: DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6314: DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6315: shift += gsize;
6316: }
6317: ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6318: for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6319: return(0);
6320: }
6323: /*@
6324: DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6326: Input Parameter:
6327: . dm - The DMPlex object
6329: Output Parameter:
6330: . ranks - The rank field
6332: Options Database Keys:
6333: . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6335: Level: intermediate
6337: .seealso: DMView()
6338: @*/
6339: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6340: {
6341: DM rdm;
6342: PetscFE fe;
6343: PetscScalar *r;
6344: PetscMPIInt rank;
6345: PetscInt dim, cStart, cEnd, c;
6351: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6352: DMClone(dm, &rdm);
6353: DMGetDimension(rdm, &dim);
6354: PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6355: PetscObjectSetName((PetscObject) fe, "rank");
6356: DMSetField(rdm, 0, NULL, (PetscObject) fe);
6357: PetscFEDestroy(&fe);
6358: DMCreateDS(rdm);
6359: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6360: DMCreateGlobalVector(rdm, ranks);
6361: PetscObjectSetName((PetscObject) *ranks, "partition");
6362: VecGetArray(*ranks, &r);
6363: for (c = cStart; c < cEnd; ++c) {
6364: PetscScalar *lr;
6366: DMPlexPointGlobalRef(rdm, c, r, &lr);
6367: *lr = rank;
6368: }
6369: VecRestoreArray(*ranks, &r);
6370: DMDestroy(&rdm);
6371: return(0);
6372: }
6374: /*@
6375: DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
6377: Input Parameters:
6378: + dm - The DMPlex
6379: - label - The DMLabel
6381: Output Parameter:
6382: . val - The label value field
6384: Options Database Keys:
6385: . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
6387: Level: intermediate
6389: .seealso: DMView()
6390: @*/
6391: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6392: {
6393: DM rdm;
6394: PetscFE fe;
6395: PetscScalar *v;
6396: PetscInt dim, cStart, cEnd, c;
6403: DMClone(dm, &rdm);
6404: DMGetDimension(rdm, &dim);
6405: PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6406: PetscObjectSetName((PetscObject) fe, "label_value");
6407: DMSetField(rdm, 0, NULL, (PetscObject) fe);
6408: PetscFEDestroy(&fe);
6409: DMCreateDS(rdm);
6410: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6411: DMCreateGlobalVector(rdm, val);
6412: PetscObjectSetName((PetscObject) *val, "label_value");
6413: VecGetArray(*val, &v);
6414: for (c = cStart; c < cEnd; ++c) {
6415: PetscScalar *lv;
6416: PetscInt cval;
6418: DMPlexPointGlobalRef(rdm, c, v, &lv);
6419: DMLabelGetValue(label, c, &cval);
6420: *lv = cval;
6421: }
6422: VecRestoreArray(*val, &v);
6423: DMDestroy(&rdm);
6424: return(0);
6425: }
6427: /*@
6428: DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6430: Input Parameter:
6431: . dm - The DMPlex object
6433: Note: This is a useful diagnostic when creating meshes programmatically.
6435: Level: developer
6437: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6438: @*/
6439: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6440: {
6441: PetscSection coneSection, supportSection;
6442: const PetscInt *cone, *support;
6443: PetscInt coneSize, c, supportSize, s;
6444: PetscInt pStart, pEnd, p, pp, csize, ssize;
6445: PetscBool storagecheck = PETSC_TRUE;
6446: PetscErrorCode ierr;
6450: DMPlexGetConeSection(dm, &coneSection);
6451: DMPlexGetSupportSection(dm, &supportSection);
6452: /* Check that point p is found in the support of its cone points, and vice versa */
6453: DMPlexGetChart(dm, &pStart, &pEnd);
6454: for (p = pStart; p < pEnd; ++p) {
6455: DMPlexGetConeSize(dm, p, &coneSize);
6456: DMPlexGetCone(dm, p, &cone);
6457: for (c = 0; c < coneSize; ++c) {
6458: PetscBool dup = PETSC_FALSE;
6459: PetscInt d;
6460: for (d = c-1; d >= 0; --d) {
6461: if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6462: }
6463: DMPlexGetSupportSize(dm, cone[c], &supportSize);
6464: DMPlexGetSupport(dm, cone[c], &support);
6465: for (s = 0; s < supportSize; ++s) {
6466: if (support[s] == p) break;
6467: }
6468: if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6469: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6470: for (s = 0; s < coneSize; ++s) {
6471: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6472: }
6473: PetscPrintf(PETSC_COMM_SELF, "\n");
6474: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6475: for (s = 0; s < supportSize; ++s) {
6476: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6477: }
6478: PetscPrintf(PETSC_COMM_SELF, "\n");
6479: if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6480: else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6481: }
6482: }
6483: DMPlexGetTreeParent(dm, p, &pp, NULL);
6484: if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6485: DMPlexGetSupportSize(dm, p, &supportSize);
6486: DMPlexGetSupport(dm, p, &support);
6487: for (s = 0; s < supportSize; ++s) {
6488: DMPlexGetConeSize(dm, support[s], &coneSize);
6489: DMPlexGetCone(dm, support[s], &cone);
6490: for (c = 0; c < coneSize; ++c) {
6491: DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
6492: if (cone[c] != pp) { c = 0; break; }
6493: if (cone[c] == p) break;
6494: }
6495: if (c >= coneSize) {
6496: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6497: for (c = 0; c < supportSize; ++c) {
6498: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6499: }
6500: PetscPrintf(PETSC_COMM_SELF, "\n");
6501: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6502: for (c = 0; c < coneSize; ++c) {
6503: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6504: }
6505: PetscPrintf(PETSC_COMM_SELF, "\n");
6506: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6507: }
6508: }
6509: }
6510: if (storagecheck) {
6511: PetscSectionGetStorageSize(coneSection, &csize);
6512: PetscSectionGetStorageSize(supportSection, &ssize);
6513: if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6514: }
6515: return(0);
6516: }
6518: /*@
6519: DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6521: Input Parameters:
6522: + dm - The DMPlex object
6523: . isSimplex - Are the cells simplices or tensor products
6524: - cellHeight - Normally 0
6526: Note: This is a useful diagnostic when creating meshes programmatically.
6528: Level: developer
6530: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6531: @*/
6532: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6533: {
6534: PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6539: DMGetDimension(dm, &dim);
6540: switch (dim) {
6541: case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6542: case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6543: case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6544: default:
6545: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6546: }
6547: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6548: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6549: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6550: cMax = cMax >= 0 ? cMax : cEnd;
6551: for (c = cStart; c < cMax; ++c) {
6552: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6554: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6555: for (cl = 0; cl < closureSize*2; cl += 2) {
6556: const PetscInt p = closure[cl];
6557: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6558: }
6559: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6560: if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D", c, coneSize, numCorners);
6561: }
6562: for (c = cMax; c < cEnd; ++c) {
6563: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6565: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6566: for (cl = 0; cl < closureSize*2; cl += 2) {
6567: const PetscInt p = closure[cl];
6568: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6569: }
6570: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6571: if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has %D vertices > %D", c, coneSize, numHybridCorners);
6572: }
6573: return(0);
6574: }
6576: /*@
6577: DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6579: Input Parameters:
6580: + dm - The DMPlex object
6581: . isSimplex - Are the cells simplices or tensor products
6582: - cellHeight - Normally 0
6584: Note: This is a useful diagnostic when creating meshes programmatically.
6586: Level: developer
6588: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6589: @*/
6590: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6591: {
6592: PetscInt pMax[4];
6593: PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h;
6598: DMGetDimension(dm, &dim);
6599: DMPlexGetDepth(dm, &depth);
6600: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6601: DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6602: for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
6603: DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6604: for (c = cStart; c < cEnd; ++c) {
6605: const PetscInt *cone, *ornt, *faces;
6606: PetscInt numFaces, faceSize, coneSize,f;
6607: PetscInt *closure = NULL, closureSize, cl, numCorners = 0;
6609: if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6610: DMPlexGetConeSize(dm, c, &coneSize);
6611: DMPlexGetCone(dm, c, &cone);
6612: DMPlexGetConeOrientation(dm, c, &ornt);
6613: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6614: for (cl = 0; cl < closureSize*2; cl += 2) {
6615: const PetscInt p = closure[cl];
6616: if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6617: }
6618: DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6619: if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6620: for (f = 0; f < numFaces; ++f) {
6621: PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6623: DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6624: for (cl = 0; cl < fclosureSize*2; cl += 2) {
6625: const PetscInt p = fclosure[cl];
6626: if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6627: }
6628: 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);
6629: for (v = 0; v < fnumCorners; ++v) {
6630: 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]);
6631: }
6632: DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6633: }
6634: DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6635: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6636: }
6637: }
6638: return(0);
6639: }
6641: /*@
6642: DMPlexCheckGeometry - Check the geometry of mesh cells
6644: Input Parameter:
6645: . dm - The DMPlex object
6647: Note: This is a useful diagnostic when creating meshes programmatically.
6649: Level: developer
6651: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
6652: @*/
6653: PetscErrorCode DMPlexCheckGeometry(DM dm)
6654: {
6655: PetscReal detJ, J[9], refVol = 1.0;
6656: PetscReal vol;
6657: PetscInt dim, depth, d, cStart, cEnd, c;
6661: DMGetDimension(dm, &dim);
6662: DMPlexGetDepth(dm, &depth);
6663: for (d = 0; d < dim; ++d) refVol *= 2.0;
6664: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6665: for (c = cStart; c < cEnd; ++c) {
6666: DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
6667: if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
6668: PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
6669: if (depth > 1) {
6670: DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
6671: if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
6672: PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
6673: }
6674: }
6675: return(0);
6676: }
6678: static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
6679: {
6680: PetscInt i,l,n;
6681: const PetscInt *cone;
6685: *missingPoint = -1;
6686: DMPlexGetConeSize(dm, p, &n);
6687: DMPlexGetCone(dm, p, &cone);
6688: for (i=0; i<n; i++) {
6689: PetscFindInt(cone[i], npoints, points, &l);
6690: if (l < 0) {
6691: *missingPoint = cone[i];
6692: break;
6693: }
6694: }
6695: return(0);
6696: }
6698: /*@
6699: DMPlexCheckPointSF - Check that several sufficient conditions are met for the point SF of this plex.
6701: Input Parameters:
6702: . dm - The DMPlex object
6704: Note: This is mainly intended for debugging/testing purposes.
6706: Level: developer
6708: .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6709: @*/
6710: PetscErrorCode DMPlexCheckPointSF(DM dm)
6711: {
6712: PetscSF sf;
6713: PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
6714: const PetscInt *locals;
6719: DMPlexGetDepth(dm, &depth);
6720: DMGetPointSF(dm, &sf);
6721: PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);
6723: /* 1) check there are no faces in 2D, cells in 3D, in interface */
6724: DMPlexGetVTKCellHeight(dm, &d);
6725: DMPlexGetHeightStratum(dm, d, &plo, &phi);
6726: for (i=0; i<nleaves; i++) {
6727: p = locals[i];
6728: if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
6729: }
6731: /* 2) if some point is in interface, then all its cone points must be also in interface */
6732: for (i=0; i<nleaves; i++) {
6733: p = locals[i];
6734: DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);
6735: if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
6736: }
6737: return(0);
6738: }
6740: typedef struct cell_stats
6741: {
6742: PetscReal min, max, sum, squaresum;
6743: PetscInt count;
6744: } cell_stats_t;
6746: static void cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
6747: {
6748: PetscInt i, N = *len;
6750: for (i = 0; i < N; i++) {
6751: cell_stats_t *A = (cell_stats_t *) a;
6752: cell_stats_t *B = (cell_stats_t *) b;
6754: B->min = PetscMin(A->min,B->min);
6755: B->max = PetscMax(A->max,B->max);
6756: B->sum += A->sum;
6757: B->squaresum += A->squaresum;
6758: B->count += A->count;
6759: }
6760: }
6762: /*@
6763: DMPlexCheckCellShape - Checks the Jacobian of the mapping and computes some minimal statistics.
6765: Input Parameters:
6766: + dm - The DMPlex object
6767: - output - If true, statistics will be displayed on stdout
6769: Note: This is mainly intended for debugging/testing purposes.
6771: Level: developer
6773: .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6774: @*/
6775: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output)
6776: {
6777: PetscMPIInt rank,size;
6778: PetscInt dim, c, cStart, cEnd, cMax, count = 0;
6779: cell_stats_t stats, globalStats;
6780: PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
6781: MPI_Comm comm = PetscObjectComm((PetscObject)dm);
6782: DM dmCoarse;
6787: stats.min = PETSC_MAX_REAL;
6788: stats.max = PETSC_MIN_REAL;
6789: stats.sum = stats.squaresum = 0.;
6790: stats.count = 0;
6792: DMGetCoordinateDim(dm,&dim);
6793: PetscMalloc2(dim * dim, &J, dim * dim, &invJ);
6794: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
6795: DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
6796: cMax = cMax < 0 ? cEnd : cMax;
6797: for (c = cStart; c < cMax; c++) {
6798: PetscInt i;
6799: PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
6801: DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
6802: if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
6803: for (i = 0; i < dim * dim; i++) {
6804: frobJ += J[i] * J[i];
6805: frobInvJ += invJ[i] * invJ[i];
6806: }
6807: cond2 = frobJ * frobInvJ;
6808: cond = PetscSqrtReal(cond2);
6810: stats.min = PetscMin(stats.min,cond);
6811: stats.max = PetscMax(stats.max,cond);
6812: stats.sum += cond;
6813: stats.squaresum += cond2;
6814: stats.count++;
6815: }
6817: MPI_Comm_size(comm,&size);
6818: if (size > 1) {
6819: PetscMPIInt blockLengths[2] = {4,1};
6820: MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
6821: MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType;
6822: MPI_Op statReduce;
6824: MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
6825: MPI_Type_commit(&statType);
6826: MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
6827: MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
6828: MPI_Op_free(&statReduce);
6829: MPI_Type_free(&statType);
6830: } else {
6831: PetscMemcpy(&globalStats,&stats,sizeof(stats));
6832: }
6834: MPI_Comm_rank(comm,&rank);
6835: if (!rank) {
6836: count = globalStats.count;
6837: min = globalStats.min;
6838: max = globalStats.max;
6839: mean = globalStats.sum / globalStats.count;
6840: stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
6841: }
6843: if (output) {
6844: PetscPrintf(comm,"Mesh with %D cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double) min, (double) max, (double) mean, (double) stdev);
6845: }
6846: PetscFree2(J,invJ);
6848: DMGetCoarseDM(dm,&dmCoarse);
6849: if (dmCoarse) {
6850: PetscBool isplex;
6852: PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
6853: if (isplex) {
6854: DMPlexCheckCellShape(dmCoarse,output);
6855: }
6856: }
6857: return(0);
6858: }
6860: /* Pointwise interpolation
6861: Just code FEM for now
6862: u^f = I u^c
6863: sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6864: u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6865: I_{ij} = psi^f_i phi^c_j
6866: */
6867: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6868: {
6869: PetscSection gsc, gsf;
6870: PetscInt m, n;
6871: void *ctx;
6872: DM cdm;
6873: PetscBool regular, ismatis;
6877: DMGetGlobalSection(dmFine, &gsf);
6878: PetscSectionGetConstrainedStorageSize(gsf, &m);
6879: DMGetGlobalSection(dmCoarse, &gsc);
6880: PetscSectionGetConstrainedStorageSize(gsc, &n);
6882: PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
6883: MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6884: MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6885: MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
6886: DMGetApplicationContext(dmFine, &ctx);
6888: DMGetCoarseDM(dmFine, &cdm);
6889: DMPlexGetRegularRefinement(dmFine, ®ular);
6890: if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6891: else {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6892: MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6893: if (scaling) {
6894: /* Use naive scaling */
6895: DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6896: }
6897: return(0);
6898: }
6900: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6901: {
6903: VecScatter ctx;
6906: DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6907: MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6908: VecScatterDestroy(&ctx);
6909: return(0);
6910: }
6912: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6913: {
6914: PetscSection gsc, gsf;
6915: PetscInt m, n;
6916: void *ctx;
6917: DM cdm;
6918: PetscBool regular;
6922: DMGetGlobalSection(dmFine, &gsf);
6923: PetscSectionGetConstrainedStorageSize(gsf, &m);
6924: DMGetGlobalSection(dmCoarse, &gsc);
6925: PetscSectionGetConstrainedStorageSize(gsc, &n);
6927: MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6928: MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6929: MatSetType(*mass, dmCoarse->mattype);
6930: DMGetApplicationContext(dmFine, &ctx);
6932: DMGetCoarseDM(dmFine, &cdm);
6933: DMPlexGetRegularRefinement(dmFine, ®ular);
6934: if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6935: else {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6936: MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6937: return(0);
6938: }
6940: /*@
6941: DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6943: Input Parameter:
6944: . dm - The DMPlex object
6946: Output Parameter:
6947: . regular - The flag
6949: Level: intermediate
6951: .seealso: DMPlexSetRegularRefinement()
6952: @*/
6953: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6954: {
6958: *regular = ((DM_Plex *) dm->data)->regularRefinement;
6959: return(0);
6960: }
6962: /*@
6963: DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6965: Input Parameters:
6966: + dm - The DMPlex object
6967: - regular - The flag
6969: Level: intermediate
6971: .seealso: DMPlexGetRegularRefinement()
6972: @*/
6973: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6974: {
6977: ((DM_Plex *) dm->data)->regularRefinement = regular;
6978: return(0);
6979: }
6981: /* anchors */
6982: /*@
6983: DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to
6984: call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
6986: not collective
6988: Input Parameters:
6989: . dm - The DMPlex object
6991: Output Parameters:
6992: + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
6993: - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
6996: Level: intermediate
6998: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6999: @*/
7000: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7001: {
7002: DM_Plex *plex = (DM_Plex *)dm->data;
7007: if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7008: if (anchorSection) *anchorSection = plex->anchorSection;
7009: if (anchorIS) *anchorIS = plex->anchorIS;
7010: return(0);
7011: }
7013: /*@
7014: DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions,
7015: when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
7016: point's degrees of freedom to be a linear combination of other points' degrees of freedom.
7018: After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
7019: DMGetConstraints() and filling in the entries in the constraint matrix.
7021: collective on dm
7023: Input Parameters:
7024: + dm - The DMPlex object
7025: . 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).
7026: - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative).
7028: The reference counts of anchorSection and anchorIS are incremented.
7030: Level: intermediate
7032: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7033: @*/
7034: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7035: {
7036: DM_Plex *plex = (DM_Plex *)dm->data;
7037: PetscMPIInt result;
7042: if (anchorSection) {
7044: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7045: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7046: }
7047: if (anchorIS) {
7049: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7050: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7051: }
7053: PetscObjectReference((PetscObject)anchorSection);
7054: PetscSectionDestroy(&plex->anchorSection);
7055: plex->anchorSection = anchorSection;
7057: PetscObjectReference((PetscObject)anchorIS);
7058: ISDestroy(&plex->anchorIS);
7059: plex->anchorIS = anchorIS;
7061: #if defined(PETSC_USE_DEBUG)
7062: if (anchorIS && anchorSection) {
7063: PetscInt size, a, pStart, pEnd;
7064: const PetscInt *anchors;
7066: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7067: ISGetLocalSize(anchorIS,&size);
7068: ISGetIndices(anchorIS,&anchors);
7069: for (a = 0; a < size; a++) {
7070: PetscInt p;
7072: p = anchors[a];
7073: if (p >= pStart && p < pEnd) {
7074: PetscInt dof;
7076: PetscSectionGetDof(anchorSection,p,&dof);
7077: if (dof) {
7078: PetscErrorCode ierr2;
7080: ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7081: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7082: }
7083: }
7084: }
7085: ISRestoreIndices(anchorIS,&anchors);
7086: }
7087: #endif
7088: /* reset the generic constraints */
7089: DMSetDefaultConstraints(dm,NULL,NULL);
7090: return(0);
7091: }
7093: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7094: {
7095: PetscSection anchorSection;
7096: PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
7101: DMPlexGetAnchors(dm,&anchorSection,NULL);
7102: PetscSectionCreate(PETSC_COMM_SELF,cSec);
7103: PetscSectionGetNumFields(section,&numFields);
7104: if (numFields) {
7105: PetscInt f;
7106: PetscSectionSetNumFields(*cSec,numFields);
7108: for (f = 0; f < numFields; f++) {
7109: PetscInt numComp;
7111: PetscSectionGetFieldComponents(section,f,&numComp);
7112: PetscSectionSetFieldComponents(*cSec,f,numComp);
7113: }
7114: }
7115: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7116: PetscSectionGetChart(section,&sStart,&sEnd);
7117: pStart = PetscMax(pStart,sStart);
7118: pEnd = PetscMin(pEnd,sEnd);
7119: pEnd = PetscMax(pStart,pEnd);
7120: PetscSectionSetChart(*cSec,pStart,pEnd);
7121: for (p = pStart; p < pEnd; p++) {
7122: PetscSectionGetDof(anchorSection,p,&dof);
7123: if (dof) {
7124: PetscSectionGetDof(section,p,&dof);
7125: PetscSectionSetDof(*cSec,p,dof);
7126: for (f = 0; f < numFields; f++) {
7127: PetscSectionGetFieldDof(section,p,f,&dof);
7128: PetscSectionSetFieldDof(*cSec,p,f,dof);
7129: }
7130: }
7131: }
7132: PetscSectionSetUp(*cSec);
7133: return(0);
7134: }
7136: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7137: {
7138: PetscSection aSec;
7139: PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7140: const PetscInt *anchors;
7141: PetscInt numFields, f;
7142: IS aIS;
7147: PetscSectionGetStorageSize(cSec, &m);
7148: PetscSectionGetStorageSize(section, &n);
7149: MatCreate(PETSC_COMM_SELF,cMat);
7150: MatSetSizes(*cMat,m,n,m,n);
7151: MatSetType(*cMat,MATSEQAIJ);
7152: DMPlexGetAnchors(dm,&aSec,&aIS);
7153: ISGetIndices(aIS,&anchors);
7154: /* cSec will be a subset of aSec and section */
7155: PetscSectionGetChart(cSec,&pStart,&pEnd);
7156: PetscMalloc1(m+1,&i);
7157: i[0] = 0;
7158: PetscSectionGetNumFields(section,&numFields);
7159: for (p = pStart; p < pEnd; p++) {
7160: PetscInt rDof, rOff, r;
7162: PetscSectionGetDof(aSec,p,&rDof);
7163: if (!rDof) continue;
7164: PetscSectionGetOffset(aSec,p,&rOff);
7165: if (numFields) {
7166: for (f = 0; f < numFields; f++) {
7167: annz = 0;
7168: for (r = 0; r < rDof; r++) {
7169: a = anchors[rOff + r];
7170: PetscSectionGetFieldDof(section,a,f,&aDof);
7171: annz += aDof;
7172: }
7173: PetscSectionGetFieldDof(cSec,p,f,&dof);
7174: PetscSectionGetFieldOffset(cSec,p,f,&off);
7175: for (q = 0; q < dof; q++) {
7176: i[off + q + 1] = i[off + q] + annz;
7177: }
7178: }
7179: }
7180: else {
7181: annz = 0;
7182: for (q = 0; q < dof; q++) {
7183: a = anchors[off + q];
7184: PetscSectionGetDof(section,a,&aDof);
7185: annz += aDof;
7186: }
7187: PetscSectionGetDof(cSec,p,&dof);
7188: PetscSectionGetOffset(cSec,p,&off);
7189: for (q = 0; q < dof; q++) {
7190: i[off + q + 1] = i[off + q] + annz;
7191: }
7192: }
7193: }
7194: nnz = i[m];
7195: PetscMalloc1(nnz,&j);
7196: offset = 0;
7197: for (p = pStart; p < pEnd; p++) {
7198: if (numFields) {
7199: for (f = 0; f < numFields; f++) {
7200: PetscSectionGetFieldDof(cSec,p,f,&dof);
7201: for (q = 0; q < dof; q++) {
7202: PetscInt rDof, rOff, r;
7203: PetscSectionGetDof(aSec,p,&rDof);
7204: PetscSectionGetOffset(aSec,p,&rOff);
7205: for (r = 0; r < rDof; r++) {
7206: PetscInt s;
7208: a = anchors[rOff + r];
7209: PetscSectionGetFieldDof(section,a,f,&aDof);
7210: PetscSectionGetFieldOffset(section,a,f,&aOff);
7211: for (s = 0; s < aDof; s++) {
7212: j[offset++] = aOff + s;
7213: }
7214: }
7215: }
7216: }
7217: }
7218: else {
7219: PetscSectionGetDof(cSec,p,&dof);
7220: for (q = 0; q < dof; q++) {
7221: PetscInt rDof, rOff, r;
7222: PetscSectionGetDof(aSec,p,&rDof);
7223: PetscSectionGetOffset(aSec,p,&rOff);
7224: for (r = 0; r < rDof; r++) {
7225: PetscInt s;
7227: a = anchors[rOff + r];
7228: PetscSectionGetDof(section,a,&aDof);
7229: PetscSectionGetOffset(section,a,&aOff);
7230: for (s = 0; s < aDof; s++) {
7231: j[offset++] = aOff + s;
7232: }
7233: }
7234: }
7235: }
7236: }
7237: MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7238: PetscFree(i);
7239: PetscFree(j);
7240: ISRestoreIndices(aIS,&anchors);
7241: return(0);
7242: }
7244: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7245: {
7246: DM_Plex *plex = (DM_Plex *)dm->data;
7247: PetscSection anchorSection, section, cSec;
7248: Mat cMat;
7253: DMPlexGetAnchors(dm,&anchorSection,NULL);
7254: if (anchorSection) {
7255: PetscInt Nf;
7257: DMGetSection(dm,§ion);
7258: DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7259: DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7260: DMGetNumFields(dm,&Nf);
7261: if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7262: DMSetDefaultConstraints(dm,cSec,cMat);
7263: PetscSectionDestroy(&cSec);
7264: MatDestroy(&cMat);
7265: }
7266: return(0);
7267: }
7269: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7270: {
7271: IS subis;
7272: PetscSection section, subsection;
7276: DMGetDefaultSection(dm, §ion);
7277: if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7278: if (!subdm) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7279: /* Create subdomain */
7280: DMPlexFilter(dm, label, value, subdm);
7281: /* Create submodel */
7282: DMPlexCreateSubpointIS(*subdm, &subis);
7283: PetscSectionCreateSubmeshSection(section, subis, &subsection);
7284: ISDestroy(&subis);
7285: DMSetDefaultSection(*subdm, subsection);
7286: PetscSectionDestroy(&subsection);
7287: DMCopyDisc(dm, *subdm);
7288: /* Create map from submodel to global model */
7289: if (is) {
7290: PetscSection sectionGlobal, subsectionGlobal;
7291: IS spIS;
7292: const PetscInt *spmap;
7293: PetscInt *subIndices;
7294: PetscInt subSize = 0, subOff = 0, pStart, pEnd, p;
7295: PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
7297: DMPlexCreateSubpointIS(*subdm, &spIS);
7298: ISGetIndices(spIS, &spmap);
7299: PetscSectionGetNumFields(section, &Nf);
7300: DMGetDefaultGlobalSection(dm, §ionGlobal);
7301: DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);
7302: PetscSectionGetChart(subsection, &pStart, &pEnd);
7303: for (p = pStart; p < pEnd; ++p) {
7304: PetscInt gdof, pSubSize = 0;
7306: PetscSectionGetDof(sectionGlobal, p, &gdof);
7307: if (gdof > 0) {
7308: for (f = 0; f < Nf; ++f) {
7309: PetscInt fdof, fcdof;
7311: PetscSectionGetFieldDof(subsection, p, f, &fdof);
7312: PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7313: pSubSize += fdof-fcdof;
7314: }
7315: subSize += pSubSize;
7316: if (pSubSize) {
7317: if (bs < 0) {
7318: bs = pSubSize;
7319: } else if (bs != pSubSize) {
7320: /* Layout does not admit a pointwise block size */
7321: bs = 1;
7322: }
7323: }
7324: }
7325: }
7326: /* Must have same blocksize on all procs (some might have no points) */
7327: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7328: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7329: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7330: else {bs = bsMinMax[0];}
7331: PetscMalloc1(subSize, &subIndices);
7332: for (p = pStart; p < pEnd; ++p) {
7333: PetscInt gdof, goff;
7335: PetscSectionGetDof(subsectionGlobal, p, &gdof);
7336: if (gdof > 0) {
7337: const PetscInt point = spmap[p];
7339: PetscSectionGetOffset(sectionGlobal, point, &goff);
7340: for (f = 0; f < Nf; ++f) {
7341: PetscInt fdof, fcdof, fc, f2, poff = 0;
7343: /* Can get rid of this loop by storing field information in the global section */
7344: for (f2 = 0; f2 < f; ++f2) {
7345: PetscSectionGetFieldDof(section, p, f2, &fdof);
7346: PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7347: poff += fdof-fcdof;
7348: }
7349: PetscSectionGetFieldDof(section, p, f, &fdof);
7350: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7351: for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7352: subIndices[subOff] = goff+poff+fc;
7353: }
7354: }
7355: }
7356: }
7357: ISRestoreIndices(spIS, &spmap);
7358: ISDestroy(&spIS);
7359: ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7360: if (bs > 1) {
7361: /* We need to check that the block size does not come from non-contiguous fields */
7362: PetscInt i, j, set = 1;
7363: for (i = 0; i < subSize; i += bs) {
7364: for (j = 0; j < bs; ++j) {
7365: if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7366: }
7367: }
7368: if (set) {ISSetBlockSize(*is, bs);}
7369: }
7370: /* Attach nullspace */
7371: for (f = 0; f < Nf; ++f) {
7372: (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7373: if ((*subdm)->nullspaceConstructors[f]) break;
7374: }
7375: if (f < Nf) {
7376: MatNullSpace nullSpace;
7378: (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7379: PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7380: MatNullSpaceDestroy(&nullSpace);
7381: }
7382: }
7383: return(0);
7384: }