Actual source code: plex.c
petsc-3.11.4 2019-09-28
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.
1523: You must also call DMPlexRestoreCone() after you finish using the returned array.
1524: DMPlexRestoreCone() is not needed/available in C.
1526: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1527: @*/
1528: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1529: {
1530: DM_Plex *mesh = (DM_Plex*) dm->data;
1531: PetscInt off;
1537: PetscSectionGetOffset(mesh->coneSection, p, &off);
1538: *cone = &mesh->cones[off];
1539: return(0);
1540: }
1542: /*@C
1543: DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
1545: Not collective
1547: Input Parameters:
1548: + dm - The DMPlex
1549: - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
1551: Output Parameter:
1552: + pConesSection - PetscSection describing the layout of pCones
1553: - pCones - An array of points which are on the in-edges for the point set p
1555: Level: intermediate
1557: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1558: @*/
1559: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1560: {
1561: PetscSection cs, newcs;
1562: PetscInt *cones;
1563: PetscInt *newarr=NULL;
1564: PetscInt n;
1565: PetscErrorCode ierr;
1568: DMPlexGetCones(dm, &cones);
1569: DMPlexGetConeSection(dm, &cs);
1570: PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1571: if (pConesSection) *pConesSection = newcs;
1572: if (pCones) {
1573: PetscSectionGetStorageSize(newcs, &n);
1574: ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1575: }
1576: return(0);
1577: }
1579: static PetscErrorCode DMPlexGetConeRecursive_Private(DM dm, PetscInt *n_inout, const PetscInt points[], PetscInt *offset_inout, PetscInt buf[])
1580: {
1581: PetscInt p, n, cn, i;
1582: const PetscInt *cone;
1586: n = *n_inout;
1587: *n_inout = 0;
1588: for (i=0; i<n; i++) {
1589: p = points[i];
1590: DMPlexGetConeSize(dm, p, &cn);
1591: if (!cn) {
1592: cn = 1;
1593: if (buf) {
1594: buf[*offset_inout] = p;
1595: ++(*offset_inout);
1596: }
1597: } else {
1598: DMPlexGetCone(dm, p, &cone);
1599: DMPlexGetConeRecursive_Private(dm, &cn, cone, offset_inout, buf);
1600: }
1601: *n_inout += cn;
1602: }
1603: return(0);
1604: }
1606: /*@C
1607: 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.
1609: Not collective
1611: Input Parameters:
1612: + dm - The DMPlex
1613: - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
1615: Output Parameter:
1616: . pCones - An array of recursively expanded cones, i.e. containing only vertices, and each of them can be present multiple times
1618: Level: advanced
1620: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple()
1621: @*/
1622: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS p, IS *pCones)
1623: {
1624: const PetscInt *arr=NULL;
1625: PetscInt *cpoints=NULL;
1626: PetscInt n, cn;
1627: PetscInt zero;
1628: PetscErrorCode ierr;
1631: ISGetLocalSize(p, &n);
1632: ISGetIndices(p, &arr);
1633: zero = 0;
1634: /* first figure out the total number of returned points */
1635: cn = n;
1636: DMPlexGetConeRecursive_Private(dm, &cn, arr, &zero, NULL);
1637: PetscMalloc1(cn, &cpoints);
1638: /* now get recursive cones themselves */
1639: DMPlexGetConeRecursive_Private(dm, &n, arr, &zero, cpoints);
1640: ISCreateGeneral(PetscObjectComm((PetscObject)p), n, cpoints, PETSC_OWN_POINTER, pCones);
1641: ISRestoreIndices(p, &arr);
1642: return(0);
1643: }
1645: /*@
1646: 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
1648: Not collective
1650: Input Parameters:
1651: + mesh - The DMPlex
1652: . p - The point, which must lie in the chart set with DMPlexSetChart()
1653: - cone - An array of points which are on the in-edges for point p
1655: Output Parameter:
1657: Note:
1658: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1660: Developer Note: Why not call this DMPlexSetCover()
1662: Level: beginner
1664: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1665: @*/
1666: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1667: {
1668: DM_Plex *mesh = (DM_Plex*) dm->data;
1669: PetscInt pStart, pEnd;
1670: PetscInt dof, off, c;
1675: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1676: PetscSectionGetDof(mesh->coneSection, p, &dof);
1678: PetscSectionGetOffset(mesh->coneSection, p, &off);
1679: 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);
1680: for (c = 0; c < dof; ++c) {
1681: 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);
1682: mesh->cones[off+c] = cone[c];
1683: }
1684: return(0);
1685: }
1687: /*@C
1688: DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
1690: Not collective
1692: Input Parameters:
1693: + mesh - The DMPlex
1694: - p - The point, which must lie in the chart set with DMPlexSetChart()
1696: Output Parameter:
1697: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1698: integer giving the prescription for cone traversal. If it is negative, the cone is
1699: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1700: the index of the cone point on which to start.
1702: Level: beginner
1704: Fortran Notes:
1705: Since it returns an array, this routine is only available in Fortran 90, and you must
1706: include petsc.h90 in your code.
1707: You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1708: DMPlexRestoreConeOrientation() is not needed/available in C.
1710: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1711: @*/
1712: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1713: {
1714: DM_Plex *mesh = (DM_Plex*) dm->data;
1715: PetscInt off;
1720: #if defined(PETSC_USE_DEBUG)
1721: {
1722: PetscInt dof;
1723: PetscSectionGetDof(mesh->coneSection, p, &dof);
1725: }
1726: #endif
1727: PetscSectionGetOffset(mesh->coneSection, p, &off);
1729: *coneOrientation = &mesh->coneOrientations[off];
1730: return(0);
1731: }
1733: /*@
1734: DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
1736: Not collective
1738: Input Parameters:
1739: + mesh - The DMPlex
1740: . p - The point, which must lie in the chart set with DMPlexSetChart()
1741: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1742: integer giving the prescription for cone traversal. If it is negative, the cone is
1743: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1744: the index of the cone point on which to start.
1746: Output Parameter:
1748: Note:
1749: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1751: Level: beginner
1753: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1754: @*/
1755: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1756: {
1757: DM_Plex *mesh = (DM_Plex*) dm->data;
1758: PetscInt pStart, pEnd;
1759: PetscInt dof, off, c;
1764: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1765: PetscSectionGetDof(mesh->coneSection, p, &dof);
1767: PetscSectionGetOffset(mesh->coneSection, p, &off);
1768: 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);
1769: for (c = 0; c < dof; ++c) {
1770: PetscInt cdof, o = coneOrientation[c];
1772: PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1773: 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);
1774: mesh->coneOrientations[off+c] = o;
1775: }
1776: return(0);
1777: }
1779: /*@
1780: DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
1782: Not collective
1784: Input Parameters:
1785: + mesh - The DMPlex
1786: . p - The point, which must lie in the chart set with DMPlexSetChart()
1787: . conePos - The local index in the cone where the point should be put
1788: - conePoint - The mesh point to insert
1790: Level: beginner
1792: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1793: @*/
1794: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1795: {
1796: DM_Plex *mesh = (DM_Plex*) dm->data;
1797: PetscInt pStart, pEnd;
1798: PetscInt dof, off;
1803: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1804: 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);
1805: 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);
1806: PetscSectionGetDof(mesh->coneSection, p, &dof);
1807: PetscSectionGetOffset(mesh->coneSection, p, &off);
1808: 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);
1809: mesh->cones[off+conePos] = conePoint;
1810: return(0);
1811: }
1813: /*@
1814: DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
1816: Not collective
1818: Input Parameters:
1819: + mesh - The DMPlex
1820: . p - The point, which must lie in the chart set with DMPlexSetChart()
1821: . conePos - The local index in the cone where the point should be put
1822: - coneOrientation - The point orientation to insert
1824: Level: beginner
1826: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1827: @*/
1828: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1829: {
1830: DM_Plex *mesh = (DM_Plex*) dm->data;
1831: PetscInt pStart, pEnd;
1832: PetscInt dof, off;
1837: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1838: 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);
1839: PetscSectionGetDof(mesh->coneSection, p, &dof);
1840: PetscSectionGetOffset(mesh->coneSection, p, &off);
1841: 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);
1842: mesh->coneOrientations[off+conePos] = coneOrientation;
1843: return(0);
1844: }
1846: /*@
1847: DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
1849: Not collective
1851: Input Parameters:
1852: + mesh - The DMPlex
1853: - p - The point, which must lie in the chart set with DMPlexSetChart()
1855: Output Parameter:
1856: . size - The support size for point p
1858: Level: beginner
1860: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1861: @*/
1862: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1863: {
1864: DM_Plex *mesh = (DM_Plex*) dm->data;
1870: PetscSectionGetDof(mesh->supportSection, p, size);
1871: return(0);
1872: }
1874: /*@
1875: DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
1877: Not collective
1879: Input Parameters:
1880: + mesh - The DMPlex
1881: . p - The point, which must lie in the chart set with DMPlexSetChart()
1882: - size - The support size for point p
1884: Output Parameter:
1886: Note:
1887: This should be called after DMPlexSetChart().
1889: Level: beginner
1891: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1892: @*/
1893: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1894: {
1895: DM_Plex *mesh = (DM_Plex*) dm->data;
1900: PetscSectionSetDof(mesh->supportSection, p, size);
1902: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1903: return(0);
1904: }
1906: /*@C
1907: DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
1909: Not collective
1911: Input Parameters:
1912: + mesh - The DMPlex
1913: - p - The point, which must lie in the chart set with DMPlexSetChart()
1915: Output Parameter:
1916: . support - An array of points which are on the out-edges for point p
1918: Level: beginner
1920: Fortran Notes:
1921: Since it returns an array, this routine is only available in Fortran 90, and you must
1922: include petsc.h90 in your code.
1923: You must also call DMPlexRestoreSupport() after you finish using the returned array.
1924: DMPlexRestoreSupport() is not needed/available in C.
1926: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1927: @*/
1928: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1929: {
1930: DM_Plex *mesh = (DM_Plex*) dm->data;
1931: PetscInt off;
1937: PetscSectionGetOffset(mesh->supportSection, p, &off);
1938: *support = &mesh->supports[off];
1939: return(0);
1940: }
1942: /*@
1943: DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
1945: Not collective
1947: Input Parameters:
1948: + mesh - The DMPlex
1949: . p - The point, which must lie in the chart set with DMPlexSetChart()
1950: - support - An array of points which are on the out-edges for point p
1952: Output Parameter:
1954: Note:
1955: This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1957: Level: beginner
1959: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1960: @*/
1961: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1962: {
1963: DM_Plex *mesh = (DM_Plex*) dm->data;
1964: PetscInt pStart, pEnd;
1965: PetscInt dof, off, c;
1970: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1971: PetscSectionGetDof(mesh->supportSection, p, &dof);
1973: PetscSectionGetOffset(mesh->supportSection, p, &off);
1974: 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);
1975: for (c = 0; c < dof; ++c) {
1976: 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);
1977: mesh->supports[off+c] = support[c];
1978: }
1979: return(0);
1980: }
1982: /*@
1983: DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
1985: Not collective
1987: Input Parameters:
1988: + mesh - The DMPlex
1989: . p - The point, which must lie in the chart set with DMPlexSetChart()
1990: . supportPos - The local index in the cone where the point should be put
1991: - supportPoint - The mesh point to insert
1993: Level: beginner
1995: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1996: @*/
1997: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1998: {
1999: DM_Plex *mesh = (DM_Plex*) dm->data;
2000: PetscInt pStart, pEnd;
2001: PetscInt dof, off;
2006: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2007: PetscSectionGetDof(mesh->supportSection, p, &dof);
2008: PetscSectionGetOffset(mesh->supportSection, p, &off);
2009: 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);
2010: 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);
2011: 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);
2012: mesh->supports[off+supportPos] = supportPoint;
2013: return(0);
2014: }
2016: /*@C
2017: DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
2019: Not collective
2021: Input Parameters:
2022: + mesh - The DMPlex
2023: . p - The point, which must lie in the chart set with DMPlexSetChart()
2024: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2025: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2027: Output Parameters:
2028: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2029: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2031: Note:
2032: If using internal storage (points is NULL on input), each call overwrites the last output.
2034: Fortran Notes:
2035: Since it returns an array, this routine is only available in Fortran 90, and you must
2036: include petsc.h90 in your code.
2038: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2040: Level: beginner
2042: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2043: @*/
2044: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2045: {
2046: DM_Plex *mesh = (DM_Plex*) dm->data;
2047: PetscInt *closure, *fifo;
2048: const PetscInt *tmp = NULL, *tmpO = NULL;
2049: PetscInt tmpSize, t;
2050: PetscInt depth = 0, maxSize;
2051: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
2052: PetscErrorCode ierr;
2056: DMPlexGetDepth(dm, &depth);
2057: /* This is only 1-level */
2058: if (useCone) {
2059: DMPlexGetConeSize(dm, p, &tmpSize);
2060: DMPlexGetCone(dm, p, &tmp);
2061: DMPlexGetConeOrientation(dm, p, &tmpO);
2062: } else {
2063: DMPlexGetSupportSize(dm, p, &tmpSize);
2064: DMPlexGetSupport(dm, p, &tmp);
2065: }
2066: if (depth == 1) {
2067: if (*points) {
2068: closure = *points;
2069: } else {
2070: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2071: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2072: }
2073: closure[0] = p; closure[1] = 0;
2074: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2075: closure[closureSize] = tmp[t];
2076: closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2077: }
2078: if (numPoints) *numPoints = closureSize/2;
2079: if (points) *points = closure;
2080: return(0);
2081: }
2082: {
2083: PetscInt c, coneSeries, s,supportSeries;
2085: c = mesh->maxConeSize;
2086: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2087: s = mesh->maxSupportSize;
2088: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2089: maxSize = 2*PetscMax(coneSeries,supportSeries);
2090: }
2091: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2092: if (*points) {
2093: closure = *points;
2094: } else {
2095: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2096: }
2097: closure[0] = p; closure[1] = 0;
2098: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2099: const PetscInt cp = tmp[t];
2100: const PetscInt co = tmpO ? tmpO[t] : 0;
2102: closure[closureSize] = cp;
2103: closure[closureSize+1] = co;
2104: fifo[fifoSize] = cp;
2105: fifo[fifoSize+1] = co;
2106: }
2107: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2108: while (fifoSize - fifoStart) {
2109: const PetscInt q = fifo[fifoStart];
2110: const PetscInt o = fifo[fifoStart+1];
2111: const PetscInt rev = o >= 0 ? 0 : 1;
2112: const PetscInt off = rev ? -(o+1) : o;
2114: if (useCone) {
2115: DMPlexGetConeSize(dm, q, &tmpSize);
2116: DMPlexGetCone(dm, q, &tmp);
2117: DMPlexGetConeOrientation(dm, q, &tmpO);
2118: } else {
2119: DMPlexGetSupportSize(dm, q, &tmpSize);
2120: DMPlexGetSupport(dm, q, &tmp);
2121: tmpO = NULL;
2122: }
2123: for (t = 0; t < tmpSize; ++t) {
2124: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
2125: const PetscInt cp = tmp[i];
2126: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2127: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2128: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2129: PetscInt co = tmpO ? tmpO[i] : 0;
2130: PetscInt c;
2132: if (rev) {
2133: PetscInt childSize, coff;
2134: DMPlexGetConeSize(dm, cp, &childSize);
2135: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2136: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2137: }
2138: /* Check for duplicate */
2139: for (c = 0; c < closureSize; c += 2) {
2140: if (closure[c] == cp) break;
2141: }
2142: if (c == closureSize) {
2143: closure[closureSize] = cp;
2144: closure[closureSize+1] = co;
2145: fifo[fifoSize] = cp;
2146: fifo[fifoSize+1] = co;
2147: closureSize += 2;
2148: fifoSize += 2;
2149: }
2150: }
2151: fifoStart += 2;
2152: }
2153: if (numPoints) *numPoints = closureSize/2;
2154: if (points) *points = closure;
2155: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2156: return(0);
2157: }
2159: /*@C
2160: 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
2162: Not collective
2164: Input Parameters:
2165: + mesh - The DMPlex
2166: . p - The point, which must lie in the chart set with DMPlexSetChart()
2167: . orientation - The orientation of the point
2168: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2169: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2171: Output Parameters:
2172: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2173: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2175: Note:
2176: If using internal storage (points is NULL on input), each call overwrites the last output.
2178: Fortran Notes:
2179: Since it returns an array, this routine is only available in Fortran 90, and you must
2180: include petsc.h90 in your code.
2182: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2184: Level: beginner
2186: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2187: @*/
2188: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2189: {
2190: DM_Plex *mesh = (DM_Plex*) dm->data;
2191: PetscInt *closure, *fifo;
2192: const PetscInt *tmp = NULL, *tmpO = NULL;
2193: PetscInt tmpSize, t;
2194: PetscInt depth = 0, maxSize;
2195: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
2196: PetscErrorCode ierr;
2200: DMPlexGetDepth(dm, &depth);
2201: /* This is only 1-level */
2202: if (useCone) {
2203: DMPlexGetConeSize(dm, p, &tmpSize);
2204: DMPlexGetCone(dm, p, &tmp);
2205: DMPlexGetConeOrientation(dm, p, &tmpO);
2206: } else {
2207: DMPlexGetSupportSize(dm, p, &tmpSize);
2208: DMPlexGetSupport(dm, p, &tmp);
2209: }
2210: if (depth == 1) {
2211: if (*points) {
2212: closure = *points;
2213: } else {
2214: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2215: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2216: }
2217: closure[0] = p; closure[1] = ornt;
2218: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2219: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2220: closure[closureSize] = tmp[i];
2221: closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2222: }
2223: if (numPoints) *numPoints = closureSize/2;
2224: if (points) *points = closure;
2225: return(0);
2226: }
2227: {
2228: PetscInt c, coneSeries, s,supportSeries;
2230: c = mesh->maxConeSize;
2231: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2232: s = mesh->maxSupportSize;
2233: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2234: maxSize = 2*PetscMax(coneSeries,supportSeries);
2235: }
2236: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2237: if (*points) {
2238: closure = *points;
2239: } else {
2240: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2241: }
2242: closure[0] = p; closure[1] = ornt;
2243: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2244: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2245: const PetscInt cp = tmp[i];
2246: PetscInt co = tmpO ? tmpO[i] : 0;
2248: if (ornt < 0) {
2249: PetscInt childSize, coff;
2250: DMPlexGetConeSize(dm, cp, &childSize);
2251: coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2252: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2253: }
2254: closure[closureSize] = cp;
2255: closure[closureSize+1] = co;
2256: fifo[fifoSize] = cp;
2257: fifo[fifoSize+1] = co;
2258: }
2259: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2260: while (fifoSize - fifoStart) {
2261: const PetscInt q = fifo[fifoStart];
2262: const PetscInt o = fifo[fifoStart+1];
2263: const PetscInt rev = o >= 0 ? 0 : 1;
2264: const PetscInt off = rev ? -(o+1) : o;
2266: if (useCone) {
2267: DMPlexGetConeSize(dm, q, &tmpSize);
2268: DMPlexGetCone(dm, q, &tmp);
2269: DMPlexGetConeOrientation(dm, q, &tmpO);
2270: } else {
2271: DMPlexGetSupportSize(dm, q, &tmpSize);
2272: DMPlexGetSupport(dm, q, &tmp);
2273: tmpO = NULL;
2274: }
2275: for (t = 0; t < tmpSize; ++t) {
2276: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
2277: const PetscInt cp = tmp[i];
2278: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2279: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2280: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2281: PetscInt co = tmpO ? tmpO[i] : 0;
2282: PetscInt c;
2284: if (rev) {
2285: PetscInt childSize, coff;
2286: DMPlexGetConeSize(dm, cp, &childSize);
2287: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2288: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2289: }
2290: /* Check for duplicate */
2291: for (c = 0; c < closureSize; c += 2) {
2292: if (closure[c] == cp) break;
2293: }
2294: if (c == closureSize) {
2295: closure[closureSize] = cp;
2296: closure[closureSize+1] = co;
2297: fifo[fifoSize] = cp;
2298: fifo[fifoSize+1] = co;
2299: closureSize += 2;
2300: fifoSize += 2;
2301: }
2302: }
2303: fifoStart += 2;
2304: }
2305: if (numPoints) *numPoints = closureSize/2;
2306: if (points) *points = closure;
2307: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2308: return(0);
2309: }
2311: /*@C
2312: DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
2314: Not collective
2316: Input Parameters:
2317: + mesh - The DMPlex
2318: . p - The point, which must lie in the chart set with DMPlexSetChart()
2319: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2320: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
2321: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
2323: Note:
2324: If not using internal storage (points is not NULL on input), this call is unnecessary
2326: Fortran Notes:
2327: Since it returns an array, this routine is only available in Fortran 90, and you must
2328: include petsc.h90 in your code.
2330: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2332: Level: beginner
2334: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2335: @*/
2336: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2337: {
2344: DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2345: if (numPoints) *numPoints = 0;
2346: return(0);
2347: }
2349: /*@
2350: DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
2352: Not collective
2354: Input Parameter:
2355: . mesh - The DMPlex
2357: Output Parameters:
2358: + maxConeSize - The maximum number of in-edges
2359: - maxSupportSize - The maximum number of out-edges
2361: Level: beginner
2363: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2364: @*/
2365: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2366: {
2367: DM_Plex *mesh = (DM_Plex*) dm->data;
2371: if (maxConeSize) *maxConeSize = mesh->maxConeSize;
2372: if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2373: return(0);
2374: }
2376: PetscErrorCode DMSetUp_Plex(DM dm)
2377: {
2378: DM_Plex *mesh = (DM_Plex*) dm->data;
2379: PetscInt size;
2384: PetscSectionSetUp(mesh->coneSection);
2385: PetscSectionGetStorageSize(mesh->coneSection, &size);
2386: PetscMalloc1(size, &mesh->cones);
2387: PetscCalloc1(size, &mesh->coneOrientations);
2388: if (mesh->maxSupportSize) {
2389: PetscSectionSetUp(mesh->supportSection);
2390: PetscSectionGetStorageSize(mesh->supportSection, &size);
2391: PetscMalloc1(size, &mesh->supports);
2392: }
2393: return(0);
2394: }
2396: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2397: {
2401: if (subdm) {DMClone(dm, subdm);}
2402: DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2403: if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2404: if (dm->useNatural && dm->sfMigration) {
2405: PetscSF sfMigrationInv,sfNatural;
2406: PetscSection section, sectionSeq;
2408: (*subdm)->sfMigration = dm->sfMigration;
2409: PetscObjectReference((PetscObject) dm->sfMigration);
2410: DMGetSection((*subdm), §ion);
2411: PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2412: PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq);
2413: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2415: DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2416: (*subdm)->sfNatural = sfNatural;
2417: PetscSectionDestroy(§ionSeq);
2418: PetscSFDestroy(&sfMigrationInv);
2419: }
2420: return(0);
2421: }
2423: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2424: {
2426: PetscInt i = 0;
2429: DMClone(dms[0], superdm);
2430: DMCreateSectionSuperDM(dms, len, is, superdm);
2431: (*superdm)->useNatural = PETSC_FALSE;
2432: for (i = 0; i < len; i++){
2433: if (dms[i]->useNatural && dms[i]->sfMigration) {
2434: PetscSF sfMigrationInv,sfNatural;
2435: PetscSection section, sectionSeq;
2437: (*superdm)->sfMigration = dms[i]->sfMigration;
2438: PetscObjectReference((PetscObject) dms[i]->sfMigration);
2439: (*superdm)->useNatural = PETSC_TRUE;
2440: DMGetSection((*superdm), §ion);
2441: PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2442: PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq);
2443: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2445: DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2446: (*superdm)->sfNatural = sfNatural;
2447: PetscSectionDestroy(§ionSeq);
2448: PetscSFDestroy(&sfMigrationInv);
2449: break;
2450: }
2451: }
2452: return(0);
2453: }
2455: /*@
2456: DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
2458: Not collective
2460: Input Parameter:
2461: . mesh - The DMPlex
2463: Output Parameter:
2465: Note:
2466: This should be called after all calls to DMPlexSetCone()
2468: Level: beginner
2470: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2471: @*/
2472: PetscErrorCode DMPlexSymmetrize(DM dm)
2473: {
2474: DM_Plex *mesh = (DM_Plex*) dm->data;
2475: PetscInt *offsets;
2476: PetscInt supportSize;
2477: PetscInt pStart, pEnd, p;
2482: if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2483: /* Calculate support sizes */
2484: DMPlexGetChart(dm, &pStart, &pEnd);
2485: for (p = pStart; p < pEnd; ++p) {
2486: PetscInt dof, off, c;
2488: PetscSectionGetDof(mesh->coneSection, p, &dof);
2489: PetscSectionGetOffset(mesh->coneSection, p, &off);
2490: for (c = off; c < off+dof; ++c) {
2491: PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2492: }
2493: }
2494: for (p = pStart; p < pEnd; ++p) {
2495: PetscInt dof;
2497: PetscSectionGetDof(mesh->supportSection, p, &dof);
2499: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2500: }
2501: PetscSectionSetUp(mesh->supportSection);
2502: /* Calculate supports */
2503: PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2504: PetscMalloc1(supportSize, &mesh->supports);
2505: PetscCalloc1(pEnd - pStart, &offsets);
2506: for (p = pStart; p < pEnd; ++p) {
2507: PetscInt dof, off, c;
2509: PetscSectionGetDof(mesh->coneSection, p, &dof);
2510: PetscSectionGetOffset(mesh->coneSection, p, &off);
2511: for (c = off; c < off+dof; ++c) {
2512: const PetscInt q = mesh->cones[c];
2513: PetscInt offS;
2515: PetscSectionGetOffset(mesh->supportSection, q, &offS);
2517: mesh->supports[offS+offsets[q]] = p;
2518: ++offsets[q];
2519: }
2520: }
2521: PetscFree(offsets);
2522: return(0);
2523: }
2525: static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt);
2527: /*@
2528: DMPlexStratify - The DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2529: can be illustrated by a Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2530: same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2531: the DAG.
2533: Collective on dm
2535: Input Parameter:
2536: . mesh - The DMPlex
2538: Output Parameter:
2540: Notes:
2541: Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2542: 1 for edges, and so on. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2543: manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed
2544: via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1.
2546: DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
2548: Level: beginner
2550: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2551: @*/
2552: PetscErrorCode DMPlexStratify(DM dm)
2553: {
2554: DM_Plex *mesh = (DM_Plex*) dm->data;
2555: DMLabel label;
2556: PetscInt pStart, pEnd, p;
2557: PetscInt numRoots = 0, numLeaves = 0;
2558: PetscInt cMax, fMax, eMax, vMax;
2563: PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2564: /* Calculate depth */
2565: DMPlexGetChart(dm, &pStart, &pEnd);
2566: DMCreateLabel(dm, "depth");
2567: DMPlexGetDepthLabel(dm, &label);
2568: /* Initialize roots and count leaves */
2569: for (p = pStart; p < pEnd; ++p) {
2570: PetscInt coneSize, supportSize;
2572: DMPlexGetConeSize(dm, p, &coneSize);
2573: DMPlexGetSupportSize(dm, p, &supportSize);
2574: if (!coneSize && supportSize) {
2575: ++numRoots;
2576: DMLabelSetValue(label, p, 0);
2577: } else if (!supportSize && coneSize) {
2578: ++numLeaves;
2579: } else if (!supportSize && !coneSize) {
2580: /* Isolated points */
2581: DMLabelSetValue(label, p, 0);
2582: }
2583: }
2584: if (numRoots + numLeaves == (pEnd - pStart)) {
2585: for (p = pStart; p < pEnd; ++p) {
2586: PetscInt coneSize, supportSize;
2588: DMPlexGetConeSize(dm, p, &coneSize);
2589: DMPlexGetSupportSize(dm, p, &supportSize);
2590: if (!supportSize && coneSize) {
2591: DMLabelSetValue(label, p, 1);
2592: }
2593: }
2594: } else {
2595: IS pointIS;
2596: PetscInt numPoints = 0, level = 0;
2598: DMLabelGetStratumIS(label, level, &pointIS);
2599: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2600: while (numPoints) {
2601: const PetscInt *points;
2602: const PetscInt newLevel = level+1;
2604: ISGetIndices(pointIS, &points);
2605: for (p = 0; p < numPoints; ++p) {
2606: const PetscInt point = points[p];
2607: const PetscInt *support;
2608: PetscInt supportSize, s;
2610: DMPlexGetSupportSize(dm, point, &supportSize);
2611: DMPlexGetSupport(dm, point, &support);
2612: for (s = 0; s < supportSize; ++s) {
2613: DMLabelSetValue(label, support[s], newLevel);
2614: }
2615: }
2616: ISRestoreIndices(pointIS, &points);
2617: ++level;
2618: ISDestroy(&pointIS);
2619: DMLabelGetStratumIS(label, level, &pointIS);
2620: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2621: else {numPoints = 0;}
2622: }
2623: ISDestroy(&pointIS);
2624: }
2625: { /* just in case there is an empty process */
2626: PetscInt numValues, maxValues = 0, v;
2628: DMLabelGetNumValues(label,&numValues);
2629: for (v = 0; v < numValues; v++) {
2630: IS pointIS;
2632: DMLabelGetStratumIS(label, v, &pointIS);
2633: if (pointIS) {
2634: PetscInt min, max, numPoints;
2635: PetscInt start;
2636: PetscBool contig;
2638: ISGetLocalSize(pointIS, &numPoints);
2639: ISGetMinMax(pointIS, &min, &max);
2640: ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2641: if (start == 0 && contig) {
2642: ISDestroy(&pointIS);
2643: ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2644: DMLabelSetStratumIS(label, v, pointIS);
2645: }
2646: }
2647: ISDestroy(&pointIS);
2648: }
2649: MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2650: for (v = numValues; v < maxValues; v++) {
2651: DMLabelAddStratum(label,v);
2652: }
2653: }
2654: PetscObjectStateGet((PetscObject) label, &mesh->depthState);
2656: DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2657: if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2658: DMLabel dimLabel;
2659: PetscInt dim;
2661: DMGetDimension(dm, &dim);
2662: DMGetLabel(dm, "dim", &dimLabel);
2663: if (!dimLabel) {
2664: DMCreateLabel(dm, "dim");
2665: DMGetLabel(dm, "dim", &dimLabel);
2666: }
2667: if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2668: if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2669: if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2670: if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2671: }
2672: PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2673: return(0);
2674: }
2676: /*@C
2677: DMPlexGetJoin - Get an array for the join of the set of points
2679: Not Collective
2681: Input Parameters:
2682: + dm - The DMPlex object
2683: . numPoints - The number of input points for the join
2684: - points - The input points
2686: Output Parameters:
2687: + numCoveredPoints - The number of points in the join
2688: - coveredPoints - The points in the join
2690: Level: intermediate
2692: Note: Currently, this is restricted to a single level join
2694: Fortran Notes:
2695: Since it returns an array, this routine is only available in Fortran 90, and you must
2696: include petsc.h90 in your code.
2698: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2700: .keywords: mesh
2701: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2702: @*/
2703: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2704: {
2705: DM_Plex *mesh = (DM_Plex*) dm->data;
2706: PetscInt *join[2];
2707: PetscInt joinSize, i = 0;
2708: PetscInt dof, off, p, c, m;
2716: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2717: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2718: /* Copy in support of first point */
2719: PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2720: PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2721: for (joinSize = 0; joinSize < dof; ++joinSize) {
2722: join[i][joinSize] = mesh->supports[off+joinSize];
2723: }
2724: /* Check each successive support */
2725: for (p = 1; p < numPoints; ++p) {
2726: PetscInt newJoinSize = 0;
2728: PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2729: PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2730: for (c = 0; c < dof; ++c) {
2731: const PetscInt point = mesh->supports[off+c];
2733: for (m = 0; m < joinSize; ++m) {
2734: if (point == join[i][m]) {
2735: join[1-i][newJoinSize++] = point;
2736: break;
2737: }
2738: }
2739: }
2740: joinSize = newJoinSize;
2741: i = 1-i;
2742: }
2743: *numCoveredPoints = joinSize;
2744: *coveredPoints = join[i];
2745: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2746: return(0);
2747: }
2749: /*@C
2750: DMPlexRestoreJoin - Restore an array for the join of the set of points
2752: Not Collective
2754: Input Parameters:
2755: + dm - The DMPlex object
2756: . numPoints - The number of input points for the join
2757: - points - The input points
2759: Output Parameters:
2760: + numCoveredPoints - The number of points in the join
2761: - coveredPoints - The points in the join
2763: Fortran Notes:
2764: Since it returns an array, this routine is only available in Fortran 90, and you must
2765: include petsc.h90 in your code.
2767: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2769: Level: intermediate
2771: .keywords: mesh
2772: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2773: @*/
2774: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2775: {
2783: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2784: if (numCoveredPoints) *numCoveredPoints = 0;
2785: return(0);
2786: }
2788: /*@C
2789: DMPlexGetFullJoin - Get an array for the join of the set of points
2791: Not Collective
2793: Input Parameters:
2794: + dm - The DMPlex object
2795: . numPoints - The number of input points for the join
2796: - points - The input points
2798: Output Parameters:
2799: + numCoveredPoints - The number of points in the join
2800: - coveredPoints - The points in the join
2802: Fortran Notes:
2803: Since it returns an array, this routine is only available in Fortran 90, and you must
2804: include petsc.h90 in your code.
2806: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2808: Level: intermediate
2810: .keywords: mesh
2811: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2812: @*/
2813: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2814: {
2815: DM_Plex *mesh = (DM_Plex*) dm->data;
2816: PetscInt *offsets, **closures;
2817: PetscInt *join[2];
2818: PetscInt depth = 0, maxSize, joinSize = 0, i = 0;
2819: PetscInt p, d, c, m, ms;
2828: DMPlexGetDepth(dm, &depth);
2829: PetscCalloc1(numPoints, &closures);
2830: DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2831: ms = mesh->maxSupportSize;
2832: maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2833: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2834: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);
2836: for (p = 0; p < numPoints; ++p) {
2837: PetscInt closureSize;
2839: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);
2841: offsets[p*(depth+2)+0] = 0;
2842: for (d = 0; d < depth+1; ++d) {
2843: PetscInt pStart, pEnd, i;
2845: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2846: for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2847: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2848: offsets[p*(depth+2)+d+1] = i;
2849: break;
2850: }
2851: }
2852: if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2853: }
2854: 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);
2855: }
2856: for (d = 0; d < depth+1; ++d) {
2857: PetscInt dof;
2859: /* Copy in support of first point */
2860: dof = offsets[d+1] - offsets[d];
2861: for (joinSize = 0; joinSize < dof; ++joinSize) {
2862: join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2863: }
2864: /* Check each successive cone */
2865: for (p = 1; p < numPoints && joinSize; ++p) {
2866: PetscInt newJoinSize = 0;
2868: dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2869: for (c = 0; c < dof; ++c) {
2870: const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2872: for (m = 0; m < joinSize; ++m) {
2873: if (point == join[i][m]) {
2874: join[1-i][newJoinSize++] = point;
2875: break;
2876: }
2877: }
2878: }
2879: joinSize = newJoinSize;
2880: i = 1-i;
2881: }
2882: if (joinSize) break;
2883: }
2884: *numCoveredPoints = joinSize;
2885: *coveredPoints = join[i];
2886: for (p = 0; p < numPoints; ++p) {
2887: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2888: }
2889: PetscFree(closures);
2890: DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2891: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2892: return(0);
2893: }
2895: /*@C
2896: DMPlexGetMeet - Get an array for the meet of the set of points
2898: Not Collective
2900: Input Parameters:
2901: + dm - The DMPlex object
2902: . numPoints - The number of input points for the meet
2903: - points - The input points
2905: Output Parameters:
2906: + numCoveredPoints - The number of points in the meet
2907: - coveredPoints - The points in the meet
2909: Level: intermediate
2911: Note: Currently, this is restricted to a single level meet
2913: Fortran Notes:
2914: Since it returns an array, this routine is only available in Fortran 90, and you must
2915: include petsc.h90 in your code.
2917: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2919: .keywords: mesh
2920: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2921: @*/
2922: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2923: {
2924: DM_Plex *mesh = (DM_Plex*) dm->data;
2925: PetscInt *meet[2];
2926: PetscInt meetSize, i = 0;
2927: PetscInt dof, off, p, c, m;
2935: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2936: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2937: /* Copy in cone of first point */
2938: PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2939: PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2940: for (meetSize = 0; meetSize < dof; ++meetSize) {
2941: meet[i][meetSize] = mesh->cones[off+meetSize];
2942: }
2943: /* Check each successive cone */
2944: for (p = 1; p < numPoints; ++p) {
2945: PetscInt newMeetSize = 0;
2947: PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2948: PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2949: for (c = 0; c < dof; ++c) {
2950: const PetscInt point = mesh->cones[off+c];
2952: for (m = 0; m < meetSize; ++m) {
2953: if (point == meet[i][m]) {
2954: meet[1-i][newMeetSize++] = point;
2955: break;
2956: }
2957: }
2958: }
2959: meetSize = newMeetSize;
2960: i = 1-i;
2961: }
2962: *numCoveringPoints = meetSize;
2963: *coveringPoints = meet[i];
2964: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2965: return(0);
2966: }
2968: /*@C
2969: DMPlexRestoreMeet - Restore an array for the meet of the set of points
2971: Not Collective
2973: Input Parameters:
2974: + dm - The DMPlex object
2975: . numPoints - The number of input points for the meet
2976: - points - The input points
2978: Output Parameters:
2979: + numCoveredPoints - The number of points in the meet
2980: - coveredPoints - The points in the meet
2982: Level: intermediate
2984: Fortran Notes:
2985: Since it returns an array, this routine is only available in Fortran 90, and you must
2986: include petsc.h90 in your code.
2988: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2990: .keywords: mesh
2991: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2992: @*/
2993: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2994: {
3002: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3003: if (numCoveredPoints) *numCoveredPoints = 0;
3004: return(0);
3005: }
3007: /*@C
3008: DMPlexGetFullMeet - Get an array for the meet of the set of points
3010: Not Collective
3012: Input Parameters:
3013: + dm - The DMPlex object
3014: . numPoints - The number of input points for the meet
3015: - points - The input points
3017: Output Parameters:
3018: + numCoveredPoints - The number of points in the meet
3019: - coveredPoints - The points in the meet
3021: Level: intermediate
3023: Fortran Notes:
3024: Since it returns an array, this routine is only available in Fortran 90, and you must
3025: include petsc.h90 in your code.
3027: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3029: .keywords: mesh
3030: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3031: @*/
3032: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3033: {
3034: DM_Plex *mesh = (DM_Plex*) dm->data;
3035: PetscInt *offsets, **closures;
3036: PetscInt *meet[2];
3037: PetscInt height = 0, maxSize, meetSize = 0, i = 0;
3038: PetscInt p, h, c, m, mc;
3047: DMPlexGetDepth(dm, &height);
3048: PetscMalloc1(numPoints, &closures);
3049: DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3050: mc = mesh->maxConeSize;
3051: maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3052: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3053: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);
3055: for (p = 0; p < numPoints; ++p) {
3056: PetscInt closureSize;
3058: DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);
3060: offsets[p*(height+2)+0] = 0;
3061: for (h = 0; h < height+1; ++h) {
3062: PetscInt pStart, pEnd, i;
3064: DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3065: for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3066: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3067: offsets[p*(height+2)+h+1] = i;
3068: break;
3069: }
3070: }
3071: if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3072: }
3073: 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);
3074: }
3075: for (h = 0; h < height+1; ++h) {
3076: PetscInt dof;
3078: /* Copy in cone of first point */
3079: dof = offsets[h+1] - offsets[h];
3080: for (meetSize = 0; meetSize < dof; ++meetSize) {
3081: meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3082: }
3083: /* Check each successive cone */
3084: for (p = 1; p < numPoints && meetSize; ++p) {
3085: PetscInt newMeetSize = 0;
3087: dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
3088: for (c = 0; c < dof; ++c) {
3089: const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
3091: for (m = 0; m < meetSize; ++m) {
3092: if (point == meet[i][m]) {
3093: meet[1-i][newMeetSize++] = point;
3094: break;
3095: }
3096: }
3097: }
3098: meetSize = newMeetSize;
3099: i = 1-i;
3100: }
3101: if (meetSize) break;
3102: }
3103: *numCoveredPoints = meetSize;
3104: *coveredPoints = meet[i];
3105: for (p = 0; p < numPoints; ++p) {
3106: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3107: }
3108: PetscFree(closures);
3109: DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3110: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3111: return(0);
3112: }
3114: /*@C
3115: DMPlexEqual - Determine if two DMs have the same topology
3117: Not Collective
3119: Input Parameters:
3120: + dmA - A DMPlex object
3121: - dmB - A DMPlex object
3123: Output Parameters:
3124: . equal - PETSC_TRUE if the topologies are identical
3126: Level: intermediate
3128: Notes:
3129: We are not solving graph isomorphism, so we do not permutation.
3131: .keywords: mesh
3132: .seealso: DMPlexGetCone()
3133: @*/
3134: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3135: {
3136: PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
3144: *equal = PETSC_FALSE;
3145: DMPlexGetDepth(dmA, &depth);
3146: DMPlexGetDepth(dmB, &depthB);
3147: if (depth != depthB) return(0);
3148: DMPlexGetChart(dmA, &pStart, &pEnd);
3149: DMPlexGetChart(dmB, &pStartB, &pEndB);
3150: if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3151: for (p = pStart; p < pEnd; ++p) {
3152: const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3153: PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s;
3155: DMPlexGetConeSize(dmA, p, &coneSize);
3156: DMPlexGetCone(dmA, p, &cone);
3157: DMPlexGetConeOrientation(dmA, p, &ornt);
3158: DMPlexGetConeSize(dmB, p, &coneSizeB);
3159: DMPlexGetCone(dmB, p, &coneB);
3160: DMPlexGetConeOrientation(dmB, p, &orntB);
3161: if (coneSize != coneSizeB) return(0);
3162: for (c = 0; c < coneSize; ++c) {
3163: if (cone[c] != coneB[c]) return(0);
3164: if (ornt[c] != orntB[c]) return(0);
3165: }
3166: DMPlexGetSupportSize(dmA, p, &supportSize);
3167: DMPlexGetSupport(dmA, p, &support);
3168: DMPlexGetSupportSize(dmB, p, &supportSizeB);
3169: DMPlexGetSupport(dmB, p, &supportB);
3170: if (supportSize != supportSizeB) return(0);
3171: for (s = 0; s < supportSize; ++s) {
3172: if (support[s] != supportB[s]) return(0);
3173: }
3174: }
3175: *equal = PETSC_TRUE;
3176: return(0);
3177: }
3179: /*@C
3180: DMPlexGetNumFaceVertices - Returns the number of vertices on a face
3182: Not Collective
3184: Input Parameters:
3185: + dm - The DMPlex
3186: . cellDim - The cell dimension
3187: - numCorners - The number of vertices on a cell
3189: Output Parameters:
3190: . numFaceVertices - The number of vertices on a face
3192: Level: developer
3194: Notes:
3195: Of course this can only work for a restricted set of symmetric shapes
3197: .seealso: DMPlexGetCone()
3198: @*/
3199: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3200: {
3201: MPI_Comm comm;
3205: PetscObjectGetComm((PetscObject)dm,&comm);
3207: switch (cellDim) {
3208: case 0:
3209: *numFaceVertices = 0;
3210: break;
3211: case 1:
3212: *numFaceVertices = 1;
3213: break;
3214: case 2:
3215: switch (numCorners) {
3216: case 3: /* triangle */
3217: *numFaceVertices = 2; /* Edge has 2 vertices */
3218: break;
3219: case 4: /* quadrilateral */
3220: *numFaceVertices = 2; /* Edge has 2 vertices */
3221: break;
3222: case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3223: *numFaceVertices = 3; /* Edge has 3 vertices */
3224: break;
3225: case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3226: *numFaceVertices = 3; /* Edge has 3 vertices */
3227: break;
3228: default:
3229: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3230: }
3231: break;
3232: case 3:
3233: switch (numCorners) {
3234: case 4: /* tetradehdron */
3235: *numFaceVertices = 3; /* Face has 3 vertices */
3236: break;
3237: case 6: /* tet cohesive cells */
3238: *numFaceVertices = 4; /* Face has 4 vertices */
3239: break;
3240: case 8: /* hexahedron */
3241: *numFaceVertices = 4; /* Face has 4 vertices */
3242: break;
3243: case 9: /* tet cohesive Lagrange cells */
3244: *numFaceVertices = 6; /* Face has 6 vertices */
3245: break;
3246: case 10: /* quadratic tetrahedron */
3247: *numFaceVertices = 6; /* Face has 6 vertices */
3248: break;
3249: case 12: /* hex cohesive Lagrange cells */
3250: *numFaceVertices = 6; /* Face has 6 vertices */
3251: break;
3252: case 18: /* quadratic tet cohesive Lagrange cells */
3253: *numFaceVertices = 6; /* Face has 6 vertices */
3254: break;
3255: case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3256: *numFaceVertices = 9; /* Face has 9 vertices */
3257: break;
3258: default:
3259: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3260: }
3261: break;
3262: default:
3263: SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3264: }
3265: return(0);
3266: }
3268: /*@
3269: DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
3271: Not Collective
3273: Input Parameter:
3274: . dm - The DMPlex object
3276: Output Parameter:
3277: . depthLabel - The DMLabel recording point depth
3279: Level: developer
3281: .keywords: mesh, points
3282: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3283: @*/
3284: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3285: {
3291: if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3292: *depthLabel = dm->depthLabel;
3293: return(0);
3294: }
3296: /*@
3297: DMPlexGetDepth - Get the depth of the DAG representing this mesh
3299: Not Collective
3301: Input Parameter:
3302: . dm - The DMPlex object
3304: Output Parameter:
3305: . depth - The number of strata (breadth first levels) in the DAG
3307: Level: developer
3309: .keywords: mesh, points
3310: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3311: @*/
3312: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3313: {
3314: DMLabel label;
3315: PetscInt d = 0;
3321: DMPlexGetDepthLabel(dm, &label);
3322: if (label) {DMLabelGetNumValues(label, &d);}
3323: *depth = d-1;
3324: return(0);
3325: }
3327: /*@
3328: DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
3330: Not Collective
3332: Input Parameters:
3333: + dm - The DMPlex object
3334: - stratumValue - The requested depth
3336: Output Parameters:
3337: + start - The first point at this depth
3338: - end - One beyond the last point at this depth
3340: Level: developer
3342: .keywords: mesh, points
3343: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3344: @*/
3345: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3346: {
3347: DMLabel label;
3348: PetscInt pStart, pEnd;
3355: DMPlexGetChart(dm, &pStart, &pEnd);
3356: if (pStart == pEnd) return(0);
3357: if (stratumValue < 0) {
3358: if (start) *start = pStart;
3359: if (end) *end = pEnd;
3360: return(0);
3361: }
3362: DMPlexGetDepthLabel(dm, &label);
3363: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3364: DMLabelGetStratumBounds(label, stratumValue, start, end);
3365: return(0);
3366: }
3368: /*@
3369: DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3371: Not Collective
3373: Input Parameters:
3374: + dm - The DMPlex object
3375: - stratumValue - The requested height
3377: Output Parameters:
3378: + start - The first point at this height
3379: - end - One beyond the last point at this height
3381: Level: developer
3383: .keywords: mesh, points
3384: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3385: @*/
3386: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3387: {
3388: DMLabel label;
3389: PetscInt depth, pStart, pEnd;
3396: DMPlexGetChart(dm, &pStart, &pEnd);
3397: if (pStart == pEnd) return(0);
3398: if (stratumValue < 0) {
3399: if (start) *start = pStart;
3400: if (end) *end = pEnd;
3401: return(0);
3402: }
3403: DMPlexGetDepthLabel(dm, &label);
3404: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3405: DMLabelGetNumValues(label, &depth);
3406: DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3407: return(0);
3408: }
3410: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3411: {
3412: PetscSection section, s;
3413: Mat m;
3414: PetscInt maxHeight;
3418: DMClone(dm, cdm);
3419: DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3420: DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3421: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
3422: DMSetSection(*cdm, section);
3423: PetscSectionDestroy(§ion);
3424: PetscSectionCreate(PETSC_COMM_SELF, &s);
3425: MatCreate(PETSC_COMM_SELF, &m);
3426: DMSetDefaultConstraints(*cdm, s, m);
3427: PetscSectionDestroy(&s);
3428: MatDestroy(&m);
3430: DMSetNumFields(*cdm, 1);
3431: DMCreateDS(*cdm);
3432: return(0);
3433: }
3435: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3436: {
3437: Vec coordsLocal;
3438: DM coordsDM;
3442: *field = NULL;
3443: DMGetCoordinatesLocal(dm,&coordsLocal);
3444: DMGetCoordinateDM(dm,&coordsDM);
3445: if (coordsLocal && coordsDM) {
3446: DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3447: }
3448: return(0);
3449: }
3451: /*@C
3452: DMPlexGetConeSection - Return a section which describes the layout of cone data
3454: Not Collective
3456: Input Parameters:
3457: . dm - The DMPlex object
3459: Output Parameter:
3460: . section - The PetscSection object
3462: Level: developer
3464: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3465: @*/
3466: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3467: {
3468: DM_Plex *mesh = (DM_Plex*) dm->data;
3472: if (section) *section = mesh->coneSection;
3473: return(0);
3474: }
3476: /*@C
3477: DMPlexGetSupportSection - Return a section which describes the layout of support data
3479: Not Collective
3481: Input Parameters:
3482: . dm - The DMPlex object
3484: Output Parameter:
3485: . section - The PetscSection object
3487: Level: developer
3489: .seealso: DMPlexGetConeSection()
3490: @*/
3491: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3492: {
3493: DM_Plex *mesh = (DM_Plex*) dm->data;
3497: if (section) *section = mesh->supportSection;
3498: return(0);
3499: }
3501: /*@C
3502: DMPlexGetCones - Return cone data
3504: Not Collective
3506: Input Parameters:
3507: . dm - The DMPlex object
3509: Output Parameter:
3510: . cones - The cone for each point
3512: Level: developer
3514: .seealso: DMPlexGetConeSection()
3515: @*/
3516: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3517: {
3518: DM_Plex *mesh = (DM_Plex*) dm->data;
3522: if (cones) *cones = mesh->cones;
3523: return(0);
3524: }
3526: /*@C
3527: DMPlexGetConeOrientations - Return cone orientation data
3529: Not Collective
3531: Input Parameters:
3532: . dm - The DMPlex object
3534: Output Parameter:
3535: . coneOrientations - The cone orientation for each point
3537: Level: developer
3539: .seealso: DMPlexGetConeSection()
3540: @*/
3541: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3542: {
3543: DM_Plex *mesh = (DM_Plex*) dm->data;
3547: if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3548: return(0);
3549: }
3551: /******************************** FEM Support **********************************/
3553: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3554: {
3555: DMLabel label;
3556: PetscInt *perm;
3557: PetscInt dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3561: if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3562: DMGetDimension(dm, &dim);
3563: DMPlexGetDepthLabel(dm, &label);
3564: DMLabelGetValue(label, point, &depth);
3565: if (depth == 1) {eStart = point;}
3566: else if (depth == dim) {
3567: const PetscInt *cone;
3569: DMPlexGetCone(dm, point, &cone);
3570: if (dim == 2) eStart = cone[0];
3571: else if (dim == 3) {
3572: const PetscInt *cone2;
3573: DMPlexGetCone(dm, cone[0], &cone2);
3574: eStart = cone2[0];
3575: } 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);
3576: } 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);
3577: if (!section) {DMGetSection(dm, §ion);}
3578: PetscSectionGetNumFields(section, &Nf);
3579: if (dim <= 1) return(0);
3580: for (f = 0; f < Nf; ++f) {
3581: /* An order k SEM disc has k-1 dofs on an edge */
3582: PetscSectionGetFieldDof(section, eStart, f, &k);
3583: PetscSectionGetFieldComponents(section, f, &Nc);
3584: k = k/Nc + 1;
3585: size += PetscPowInt(k+1, dim)*Nc;
3586: }
3587: PetscMalloc1(size, &perm);
3588: for (f = 0; f < Nf; ++f) {
3589: switch (dim) {
3590: case 2:
3591: /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3592: PetscSectionGetFieldDof(section, eStart, f, &k);
3593: PetscSectionGetFieldComponents(section, f, &Nc);
3594: k = k/Nc + 1;
3595: /* The SEM order is
3597: v_lb, {e_b}, v_rb,
3598: e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3599: v_lt, reverse {e_t}, v_rt
3600: */
3601: {
3602: const PetscInt of = 0;
3603: const PetscInt oeb = of + PetscSqr(k-1);
3604: const PetscInt oer = oeb + (k-1);
3605: const PetscInt oet = oer + (k-1);
3606: const PetscInt oel = oet + (k-1);
3607: const PetscInt ovlb = oel + (k-1);
3608: const PetscInt ovrb = ovlb + 1;
3609: const PetscInt ovrt = ovrb + 1;
3610: const PetscInt ovlt = ovrt + 1;
3611: PetscInt o;
3613: /* bottom */
3614: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3615: for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3616: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3617: /* middle */
3618: for (i = 0; i < k-1; ++i) {
3619: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3620: 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;
3621: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3622: }
3623: /* top */
3624: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3625: for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3626: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3627: foffset = offset;
3628: }
3629: break;
3630: case 3:
3631: /* The original hex closure is
3633: {c,
3634: f_b, f_t, f_f, f_b, f_r, f_l,
3635: e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb,
3636: v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3637: */
3638: PetscSectionGetFieldDof(section, eStart, f, &k);
3639: PetscSectionGetFieldComponents(section, f, &Nc);
3640: k = k/Nc + 1;
3641: /* The SEM order is
3642: Bottom Slice
3643: v_blf, {e^{(k-1)-n}_bf}, v_brf,
3644: e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3645: v_blb, {e_bb}, v_brb,
3647: Middle Slice (j)
3648: {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3649: f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3650: e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3652: Top Slice
3653: v_tlf, {e_tf}, v_trf,
3654: e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3655: v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3656: */
3657: {
3658: const PetscInt oc = 0;
3659: const PetscInt ofb = oc + PetscSqr(k-1)*(k-1);
3660: const PetscInt oft = ofb + PetscSqr(k-1);
3661: const PetscInt off = oft + PetscSqr(k-1);
3662: const PetscInt ofk = off + PetscSqr(k-1);
3663: const PetscInt ofr = ofk + PetscSqr(k-1);
3664: const PetscInt ofl = ofr + PetscSqr(k-1);
3665: const PetscInt oebl = ofl + PetscSqr(k-1);
3666: const PetscInt oebb = oebl + (k-1);
3667: const PetscInt oebr = oebb + (k-1);
3668: const PetscInt oebf = oebr + (k-1);
3669: const PetscInt oetf = oebf + (k-1);
3670: const PetscInt oetr = oetf + (k-1);
3671: const PetscInt oetb = oetr + (k-1);
3672: const PetscInt oetl = oetb + (k-1);
3673: const PetscInt oerf = oetl + (k-1);
3674: const PetscInt oelf = oerf + (k-1);
3675: const PetscInt oelb = oelf + (k-1);
3676: const PetscInt oerb = oelb + (k-1);
3677: const PetscInt ovblf = oerb + (k-1);
3678: const PetscInt ovblb = ovblf + 1;
3679: const PetscInt ovbrb = ovblb + 1;
3680: const PetscInt ovbrf = ovbrb + 1;
3681: const PetscInt ovtlf = ovbrf + 1;
3682: const PetscInt ovtrf = ovtlf + 1;
3683: const PetscInt ovtrb = ovtrf + 1;
3684: const PetscInt ovtlb = ovtrb + 1;
3685: PetscInt o, n;
3687: /* Bottom Slice */
3688: /* bottom */
3689: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3690: for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3691: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3692: /* middle */
3693: for (i = 0; i < k-1; ++i) {
3694: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3695: 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;}
3696: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3697: }
3698: /* top */
3699: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3700: for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3701: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
3703: /* Middle Slice */
3704: for (j = 0; j < k-1; ++j) {
3705: /* bottom */
3706: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3707: 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;
3708: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3709: /* middle */
3710: for (i = 0; i < k-1; ++i) {
3711: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3712: 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;
3713: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3714: }
3715: /* top */
3716: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3717: 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;
3718: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3719: }
3721: /* Top Slice */
3722: /* bottom */
3723: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3724: for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3725: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3726: /* middle */
3727: for (i = 0; i < k-1; ++i) {
3728: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3729: for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3730: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3731: }
3732: /* top */
3733: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3734: for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3735: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
3737: foffset = offset;
3738: }
3739: break;
3740: default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3741: }
3742: }
3743: if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3744: /* Check permutation */
3745: {
3746: PetscInt *check;
3748: PetscMalloc1(size, &check);
3749: 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]);}
3750: for (i = 0; i < size; ++i) check[perm[i]] = i;
3751: for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3752: PetscFree(check);
3753: }
3754: PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3755: return(0);
3756: }
3758: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3759: {
3760: PetscDS prob;
3761: PetscInt depth, Nf, h;
3762: DMLabel label;
3766: DMGetDS(dm, &prob);
3767: Nf = prob->Nf;
3768: label = dm->depthLabel;
3769: *dspace = NULL;
3770: if (field < Nf) {
3771: PetscObject disc = prob->disc[field];
3773: if (disc->classid == PETSCFE_CLASSID) {
3774: PetscDualSpace dsp;
3776: PetscFEGetDualSpace((PetscFE)disc,&dsp);
3777: DMLabelGetNumValues(label,&depth);
3778: DMLabelGetValue(label,point,&h);
3779: h = depth - 1 - h;
3780: if (h) {
3781: PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3782: } else {
3783: *dspace = dsp;
3784: }
3785: }
3786: }
3787: return(0);
3788: }
3791: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3792: {
3793: PetscScalar *array, *vArray;
3794: const PetscInt *cone, *coneO;
3795: PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0;
3796: PetscErrorCode ierr;
3799: PetscSectionGetChart(section, &pStart, &pEnd);
3800: DMPlexGetConeSize(dm, point, &numPoints);
3801: DMPlexGetCone(dm, point, &cone);
3802: DMPlexGetConeOrientation(dm, point, &coneO);
3803: if (!values || !*values) {
3804: if ((point >= pStart) && (point < pEnd)) {
3805: PetscInt dof;
3807: PetscSectionGetDof(section, point, &dof);
3808: size += dof;
3809: }
3810: for (p = 0; p < numPoints; ++p) {
3811: const PetscInt cp = cone[p];
3812: PetscInt dof;
3814: if ((cp < pStart) || (cp >= pEnd)) continue;
3815: PetscSectionGetDof(section, cp, &dof);
3816: size += dof;
3817: }
3818: if (!values) {
3819: if (csize) *csize = size;
3820: return(0);
3821: }
3822: DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
3823: } else {
3824: array = *values;
3825: }
3826: size = 0;
3827: VecGetArray(v, &vArray);
3828: if ((point >= pStart) && (point < pEnd)) {
3829: PetscInt dof, off, d;
3830: PetscScalar *varr;
3832: PetscSectionGetDof(section, point, &dof);
3833: PetscSectionGetOffset(section, point, &off);
3834: varr = &vArray[off];
3835: for (d = 0; d < dof; ++d, ++offset) {
3836: array[offset] = varr[d];
3837: }
3838: size += dof;
3839: }
3840: for (p = 0; p < numPoints; ++p) {
3841: const PetscInt cp = cone[p];
3842: PetscInt o = coneO[p];
3843: PetscInt dof, off, d;
3844: PetscScalar *varr;
3846: if ((cp < pStart) || (cp >= pEnd)) continue;
3847: PetscSectionGetDof(section, cp, &dof);
3848: PetscSectionGetOffset(section, cp, &off);
3849: varr = &vArray[off];
3850: if (o >= 0) {
3851: for (d = 0; d < dof; ++d, ++offset) {
3852: array[offset] = varr[d];
3853: }
3854: } else {
3855: for (d = dof-1; d >= 0; --d, ++offset) {
3856: array[offset] = varr[d];
3857: }
3858: }
3859: size += dof;
3860: }
3861: VecRestoreArray(v, &vArray);
3862: if (!*values) {
3863: if (csize) *csize = size;
3864: *values = array;
3865: } else {
3866: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3867: *csize = size;
3868: }
3869: return(0);
3870: }
3872: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3873: {
3874: const PetscInt *cla;
3875: PetscInt np, *pts = NULL;
3879: PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3880: if (!*clPoints) {
3881: PetscInt pStart, pEnd, p, q;
3883: PetscSectionGetChart(section, &pStart, &pEnd);
3884: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3885: /* Compress out points not in the section */
3886: for (p = 0, q = 0; p < np; p++) {
3887: PetscInt r = pts[2*p];
3888: if ((r >= pStart) && (r < pEnd)) {
3889: pts[q*2] = r;
3890: pts[q*2+1] = pts[2*p+1];
3891: ++q;
3892: }
3893: }
3894: np = q;
3895: cla = NULL;
3896: } else {
3897: PetscInt dof, off;
3899: PetscSectionGetDof(*clSec, point, &dof);
3900: PetscSectionGetOffset(*clSec, point, &off);
3901: ISGetIndices(*clPoints, &cla);
3902: np = dof/2;
3903: pts = (PetscInt *) &cla[off];
3904: }
3905: *numPoints = np;
3906: *points = pts;
3907: *clp = cla;
3909: return(0);
3910: }
3912: static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3913: {
3917: if (!*clPoints) {
3918: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3919: } else {
3920: ISRestoreIndices(*clPoints, clp);
3921: }
3922: *numPoints = 0;
3923: *points = NULL;
3924: *clSec = NULL;
3925: *clPoints = NULL;
3926: *clp = NULL;
3927: return(0);
3928: }
3930: 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[])
3931: {
3932: PetscInt offset = 0, p;
3933: const PetscInt **perms = NULL;
3934: const PetscScalar **flips = NULL;
3935: PetscErrorCode ierr;
3938: *size = 0;
3939: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3940: for (p = 0; p < numPoints; p++) {
3941: const PetscInt point = points[2*p];
3942: const PetscInt *perm = perms ? perms[p] : NULL;
3943: const PetscScalar *flip = flips ? flips[p] : NULL;
3944: PetscInt dof, off, d;
3945: const PetscScalar *varr;
3947: PetscSectionGetDof(section, point, &dof);
3948: PetscSectionGetOffset(section, point, &off);
3949: varr = &vArray[off];
3950: if (clperm) {
3951: if (perm) {
3952: for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
3953: } else {
3954: for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d];
3955: }
3956: if (flip) {
3957: for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d];
3958: }
3959: } else {
3960: if (perm) {
3961: for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
3962: } else {
3963: for (d = 0; d < dof; d++) array[offset + d ] = varr[d];
3964: }
3965: if (flip) {
3966: for (d = 0; d < dof; d++) array[offset + d ] *= flip[d];
3967: }
3968: }
3969: offset += dof;
3970: }
3971: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3972: *size = offset;
3973: return(0);
3974: }
3976: 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[])
3977: {
3978: PetscInt offset = 0, f;
3979: PetscErrorCode ierr;
3982: *size = 0;
3983: for (f = 0; f < numFields; ++f) {
3984: PetscInt p;
3985: const PetscInt **perms = NULL;
3986: const PetscScalar **flips = NULL;
3988: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3989: for (p = 0; p < numPoints; p++) {
3990: const PetscInt point = points[2*p];
3991: PetscInt fdof, foff, b;
3992: const PetscScalar *varr;
3993: const PetscInt *perm = perms ? perms[p] : NULL;
3994: const PetscScalar *flip = flips ? flips[p] : NULL;
3996: PetscSectionGetFieldDof(section, point, f, &fdof);
3997: PetscSectionGetFieldOffset(section, point, f, &foff);
3998: varr = &vArray[foff];
3999: if (clperm) {
4000: if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}}
4001: else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}}
4002: if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}}
4003: } else {
4004: if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}}
4005: else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}}
4006: if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}}
4007: }
4008: offset += fdof;
4009: }
4010: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4011: }
4012: *size = offset;
4013: return(0);
4014: }
4016: /*@C
4017: DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4019: Not collective
4021: Input Parameters:
4022: + dm - The DM
4023: . section - The section describing the layout in v, or NULL to use the default section
4024: . v - The local vector
4025: . point - The point in the DM
4026: . csize - The size of the input values array, or NULL
4027: - values - An array to use for the values, or NULL to have it allocated automatically
4029: Output Parameters:
4030: + csize - The number of values in the closure
4031: - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4033: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4034: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4035: $ assembly function, and a user may already have allocated storage for this operation.
4036: $
4037: $ A typical use could be
4038: $
4039: $ values = NULL;
4040: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4041: $ for (cl = 0; cl < clSize; ++cl) {
4042: $ <Compute on closure>
4043: $ }
4044: $ DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4045: $
4046: $ or
4047: $
4048: $ PetscMalloc1(clMaxSize, &values);
4049: $ for (p = pStart; p < pEnd; ++p) {
4050: $ clSize = clMaxSize;
4051: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4052: $ for (cl = 0; cl < clSize; ++cl) {
4053: $ <Compute on closure>
4054: $ }
4055: $ }
4056: $ PetscFree(values);
4058: Fortran Notes:
4059: Since it returns an array, this routine is only available in Fortran 90, and you must
4060: include petsc.h90 in your code.
4062: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4064: Level: intermediate
4066: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4067: @*/
4068: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4069: {
4070: PetscSection clSection;
4071: IS clPoints;
4072: PetscScalar *array;
4073: const PetscScalar *vArray;
4074: PetscInt *points = NULL;
4075: const PetscInt *clp, *perm;
4076: PetscInt depth, numFields, numPoints, size;
4077: PetscErrorCode ierr;
4081: if (!section) {DMGetSection(dm, §ion);}
4084: DMPlexGetDepth(dm, &depth);
4085: PetscSectionGetNumFields(section, &numFields);
4086: if (depth == 1 && numFields < 2) {
4087: DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4088: return(0);
4089: }
4090: /* Get points */
4091: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4092: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4093: /* Get array */
4094: if (!values || !*values) {
4095: PetscInt asize = 0, dof, p;
4097: for (p = 0; p < numPoints*2; p += 2) {
4098: PetscSectionGetDof(section, points[p], &dof);
4099: asize += dof;
4100: }
4101: if (!values) {
4102: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4103: if (csize) *csize = asize;
4104: return(0);
4105: }
4106: DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4107: } else {
4108: array = *values;
4109: }
4110: VecGetArrayRead(v, &vArray);
4111: /* Get values */
4112: if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4113: else {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4114: /* Cleanup points */
4115: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4116: /* Cleanup array */
4117: VecRestoreArrayRead(v, &vArray);
4118: if (!*values) {
4119: if (csize) *csize = size;
4120: *values = array;
4121: } else {
4122: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4123: *csize = size;
4124: }
4125: return(0);
4126: }
4128: /*@C
4129: DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4131: Not collective
4133: Input Parameters:
4134: + dm - The DM
4135: . section - The section describing the layout in v, or NULL to use the default section
4136: . v - The local vector
4137: . point - The point in the DM
4138: . csize - The number of values in the closure, or NULL
4139: - values - The array of values, which is a borrowed array and should not be freed
4141: Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4143: Fortran Notes:
4144: Since it returns an array, this routine is only available in Fortran 90, and you must
4145: include petsc.h90 in your code.
4147: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4149: Level: intermediate
4151: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4152: @*/
4153: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4154: {
4155: PetscInt size = 0;
4159: /* Should work without recalculating size */
4160: DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4161: *values = NULL;
4162: return(0);
4163: }
4165: PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;}
4166: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;}
4168: 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[])
4169: {
4170: PetscInt cdof; /* The number of constraints on this point */
4171: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4172: PetscScalar *a;
4173: PetscInt off, cind = 0, k;
4174: PetscErrorCode ierr;
4177: PetscSectionGetConstraintDof(section, point, &cdof);
4178: PetscSectionGetOffset(section, point, &off);
4179: a = &array[off];
4180: if (!cdof || setBC) {
4181: if (clperm) {
4182: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4183: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}}
4184: } else {
4185: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4186: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}}
4187: }
4188: } else {
4189: PetscSectionGetConstraintIndices(section, point, &cdofs);
4190: if (clperm) {
4191: if (perm) {for (k = 0; k < dof; ++k) {
4192: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4193: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4194: }
4195: } else {
4196: for (k = 0; k < dof; ++k) {
4197: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4198: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4199: }
4200: }
4201: } else {
4202: if (perm) {
4203: for (k = 0; k < dof; ++k) {
4204: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4205: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4206: }
4207: } else {
4208: for (k = 0; k < dof; ++k) {
4209: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4210: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4211: }
4212: }
4213: }
4214: }
4215: return(0);
4216: }
4218: 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[])
4219: {
4220: PetscInt cdof; /* The number of constraints on this point */
4221: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4222: PetscScalar *a;
4223: PetscInt off, cind = 0, k;
4224: PetscErrorCode ierr;
4227: PetscSectionGetConstraintDof(section, point, &cdof);
4228: PetscSectionGetOffset(section, point, &off);
4229: a = &array[off];
4230: if (cdof) {
4231: PetscSectionGetConstraintIndices(section, point, &cdofs);
4232: if (clperm) {
4233: if (perm) {
4234: for (k = 0; k < dof; ++k) {
4235: if ((cind < cdof) && (k == cdofs[cind])) {
4236: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4237: cind++;
4238: }
4239: }
4240: } else {
4241: for (k = 0; k < dof; ++k) {
4242: if ((cind < cdof) && (k == cdofs[cind])) {
4243: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4244: cind++;
4245: }
4246: }
4247: }
4248: } else {
4249: if (perm) {
4250: for (k = 0; k < dof; ++k) {
4251: if ((cind < cdof) && (k == cdofs[cind])) {
4252: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4253: cind++;
4254: }
4255: }
4256: } else {
4257: for (k = 0; k < dof; ++k) {
4258: if ((cind < cdof) && (k == cdofs[cind])) {
4259: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4260: cind++;
4261: }
4262: }
4263: }
4264: }
4265: }
4266: return(0);
4267: }
4269: 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[])
4270: {
4271: PetscScalar *a;
4272: PetscInt fdof, foff, fcdof, foffset = *offset;
4273: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4274: PetscInt cind = 0, b;
4275: PetscErrorCode ierr;
4278: PetscSectionGetFieldDof(section, point, f, &fdof);
4279: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4280: PetscSectionGetFieldOffset(section, point, f, &foff);
4281: a = &array[foff];
4282: if (!fcdof || setBC) {
4283: if (clperm) {
4284: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4285: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}}
4286: } else {
4287: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4288: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}}
4289: }
4290: } else {
4291: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4292: if (clperm) {
4293: if (perm) {
4294: for (b = 0; b < fdof; b++) {
4295: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4296: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4297: }
4298: } else {
4299: for (b = 0; b < fdof; b++) {
4300: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4301: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4302: }
4303: }
4304: } else {
4305: if (perm) {
4306: for (b = 0; b < fdof; b++) {
4307: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4308: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4309: }
4310: } else {
4311: for (b = 0; b < fdof; b++) {
4312: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4313: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4314: }
4315: }
4316: }
4317: }
4318: *offset += fdof;
4319: return(0);
4320: }
4322: 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[])
4323: {
4324: PetscScalar *a;
4325: PetscInt fdof, foff, fcdof, foffset = *offset;
4326: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4327: PetscInt cind = 0, ncind = 0, b;
4328: PetscBool ncSet, fcSet;
4329: PetscErrorCode ierr;
4332: PetscSectionGetFieldDof(section, point, f, &fdof);
4333: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4334: PetscSectionGetFieldOffset(section, point, f, &foff);
4335: a = &array[foff];
4336: if (fcdof) {
4337: /* We just override fcdof and fcdofs with Ncc and comps */
4338: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4339: if (clperm) {
4340: if (perm) {
4341: if (comps) {
4342: for (b = 0; b < fdof; b++) {
4343: ncSet = fcSet = PETSC_FALSE;
4344: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4345: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4346: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4347: }
4348: } else {
4349: for (b = 0; b < fdof; b++) {
4350: if ((cind < fcdof) && (b == fcdofs[cind])) {
4351: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4352: ++cind;
4353: }
4354: }
4355: }
4356: } else {
4357: if (comps) {
4358: for (b = 0; b < fdof; b++) {
4359: ncSet = fcSet = PETSC_FALSE;
4360: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4361: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4362: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}
4363: }
4364: } else {
4365: for (b = 0; b < fdof; b++) {
4366: if ((cind < fcdof) && (b == fcdofs[cind])) {
4367: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4368: ++cind;
4369: }
4370: }
4371: }
4372: }
4373: } else {
4374: if (perm) {
4375: if (comps) {
4376: for (b = 0; b < fdof; b++) {
4377: ncSet = fcSet = PETSC_FALSE;
4378: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4379: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4380: if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4381: }
4382: } else {
4383: for (b = 0; b < fdof; b++) {
4384: if ((cind < fcdof) && (b == fcdofs[cind])) {
4385: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4386: ++cind;
4387: }
4388: }
4389: }
4390: } else {
4391: if (comps) {
4392: for (b = 0; b < fdof; b++) {
4393: ncSet = fcSet = PETSC_FALSE;
4394: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4395: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4396: if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}
4397: }
4398: } else {
4399: for (b = 0; b < fdof; b++) {
4400: if ((cind < fcdof) && (b == fcdofs[cind])) {
4401: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4402: ++cind;
4403: }
4404: }
4405: }
4406: }
4407: }
4408: }
4409: *offset += fdof;
4410: return(0);
4411: }
4413: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4414: {
4415: PetscScalar *array;
4416: const PetscInt *cone, *coneO;
4417: PetscInt pStart, pEnd, p, numPoints, off, dof;
4418: PetscErrorCode ierr;
4421: PetscSectionGetChart(section, &pStart, &pEnd);
4422: DMPlexGetConeSize(dm, point, &numPoints);
4423: DMPlexGetCone(dm, point, &cone);
4424: DMPlexGetConeOrientation(dm, point, &coneO);
4425: VecGetArray(v, &array);
4426: for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4427: const PetscInt cp = !p ? point : cone[p-1];
4428: const PetscInt o = !p ? 0 : coneO[p-1];
4430: if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4431: PetscSectionGetDof(section, cp, &dof);
4432: /* ADD_VALUES */
4433: {
4434: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4435: PetscScalar *a;
4436: PetscInt cdof, coff, cind = 0, k;
4438: PetscSectionGetConstraintDof(section, cp, &cdof);
4439: PetscSectionGetOffset(section, cp, &coff);
4440: a = &array[coff];
4441: if (!cdof) {
4442: if (o >= 0) {
4443: for (k = 0; k < dof; ++k) {
4444: a[k] += values[off+k];
4445: }
4446: } else {
4447: for (k = 0; k < dof; ++k) {
4448: a[k] += values[off+dof-k-1];
4449: }
4450: }
4451: } else {
4452: PetscSectionGetConstraintIndices(section, cp, &cdofs);
4453: if (o >= 0) {
4454: for (k = 0; k < dof; ++k) {
4455: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4456: a[k] += values[off+k];
4457: }
4458: } else {
4459: for (k = 0; k < dof; ++k) {
4460: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4461: a[k] += values[off+dof-k-1];
4462: }
4463: }
4464: }
4465: }
4466: }
4467: VecRestoreArray(v, &array);
4468: return(0);
4469: }
4471: /*@C
4472: DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4474: Not collective
4476: Input Parameters:
4477: + dm - The DM
4478: . section - The section describing the layout in v, or NULL to use the default section
4479: . v - The local vector
4480: . point - The point in the DM
4481: . values - The array of values
4482: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4483: where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
4485: Fortran Notes:
4486: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4488: Level: intermediate
4490: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4491: @*/
4492: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4493: {
4494: PetscSection clSection;
4495: IS clPoints;
4496: PetscScalar *array;
4497: PetscInt *points = NULL;
4498: const PetscInt *clp, *clperm;
4499: PetscInt depth, numFields, numPoints, p;
4500: PetscErrorCode ierr;
4504: if (!section) {DMGetSection(dm, §ion);}
4507: DMPlexGetDepth(dm, &depth);
4508: PetscSectionGetNumFields(section, &numFields);
4509: if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4510: DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4511: return(0);
4512: }
4513: /* Get points */
4514: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4515: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4516: /* Get array */
4517: VecGetArray(v, &array);
4518: /* Get values */
4519: if (numFields > 0) {
4520: PetscInt offset = 0, f;
4521: for (f = 0; f < numFields; ++f) {
4522: const PetscInt **perms = NULL;
4523: const PetscScalar **flips = NULL;
4525: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4526: switch (mode) {
4527: case INSERT_VALUES:
4528: for (p = 0; p < numPoints; p++) {
4529: const PetscInt point = points[2*p];
4530: const PetscInt *perm = perms ? perms[p] : NULL;
4531: const PetscScalar *flip = flips ? flips[p] : NULL;
4532: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4533: } break;
4534: case INSERT_ALL_VALUES:
4535: for (p = 0; p < numPoints; p++) {
4536: const PetscInt point = points[2*p];
4537: const PetscInt *perm = perms ? perms[p] : NULL;
4538: const PetscScalar *flip = flips ? flips[p] : NULL;
4539: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4540: } break;
4541: case INSERT_BC_VALUES:
4542: for (p = 0; p < numPoints; p++) {
4543: const PetscInt point = points[2*p];
4544: const PetscInt *perm = perms ? perms[p] : NULL;
4545: const PetscScalar *flip = flips ? flips[p] : NULL;
4546: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4547: } break;
4548: case ADD_VALUES:
4549: for (p = 0; p < numPoints; p++) {
4550: const PetscInt point = points[2*p];
4551: const PetscInt *perm = perms ? perms[p] : NULL;
4552: const PetscScalar *flip = flips ? flips[p] : NULL;
4553: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4554: } break;
4555: case ADD_ALL_VALUES:
4556: for (p = 0; p < numPoints; p++) {
4557: const PetscInt point = points[2*p];
4558: const PetscInt *perm = perms ? perms[p] : NULL;
4559: const PetscScalar *flip = flips ? flips[p] : NULL;
4560: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4561: } break;
4562: case ADD_BC_VALUES:
4563: for (p = 0; p < numPoints; p++) {
4564: const PetscInt point = points[2*p];
4565: const PetscInt *perm = perms ? perms[p] : NULL;
4566: const PetscScalar *flip = flips ? flips[p] : NULL;
4567: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4568: } break;
4569: default:
4570: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4571: }
4572: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4573: }
4574: } else {
4575: PetscInt dof, off;
4576: const PetscInt **perms = NULL;
4577: const PetscScalar **flips = NULL;
4579: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4580: switch (mode) {
4581: case INSERT_VALUES:
4582: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4583: const PetscInt point = points[2*p];
4584: const PetscInt *perm = perms ? perms[p] : NULL;
4585: const PetscScalar *flip = flips ? flips[p] : NULL;
4586: PetscSectionGetDof(section, point, &dof);
4587: updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4588: } break;
4589: case INSERT_ALL_VALUES:
4590: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4591: const PetscInt point = points[2*p];
4592: const PetscInt *perm = perms ? perms[p] : NULL;
4593: const PetscScalar *flip = flips ? flips[p] : NULL;
4594: PetscSectionGetDof(section, point, &dof);
4595: updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array);
4596: } break;
4597: case INSERT_BC_VALUES:
4598: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4599: const PetscInt point = points[2*p];
4600: const PetscInt *perm = perms ? perms[p] : NULL;
4601: const PetscScalar *flip = flips ? flips[p] : NULL;
4602: PetscSectionGetDof(section, point, &dof);
4603: updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array);
4604: } break;
4605: case ADD_VALUES:
4606: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4607: const PetscInt point = points[2*p];
4608: const PetscInt *perm = perms ? perms[p] : NULL;
4609: const PetscScalar *flip = flips ? flips[p] : NULL;
4610: PetscSectionGetDof(section, point, &dof);
4611: updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array);
4612: } break;
4613: case ADD_ALL_VALUES:
4614: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4615: const PetscInt point = points[2*p];
4616: const PetscInt *perm = perms ? perms[p] : NULL;
4617: const PetscScalar *flip = flips ? flips[p] : NULL;
4618: PetscSectionGetDof(section, point, &dof);
4619: updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array);
4620: } break;
4621: case ADD_BC_VALUES:
4622: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4623: const PetscInt point = points[2*p];
4624: const PetscInt *perm = perms ? perms[p] : NULL;
4625: const PetscScalar *flip = flips ? flips[p] : NULL;
4626: PetscSectionGetDof(section, point, &dof);
4627: updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array);
4628: } break;
4629: default:
4630: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4631: }
4632: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4633: }
4634: /* Cleanup points */
4635: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4636: /* Cleanup array */
4637: VecRestoreArray(v, &array);
4638: return(0);
4639: }
4641: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4642: {
4643: PetscSection clSection;
4644: IS clPoints;
4645: PetscScalar *array;
4646: PetscInt *points = NULL;
4647: const PetscInt *clp, *clperm;
4648: PetscInt numFields, numPoints, p;
4649: PetscInt offset = 0, f;
4650: PetscErrorCode ierr;
4654: if (!section) {DMGetSection(dm, §ion);}
4657: PetscSectionGetNumFields(section, &numFields);
4658: /* Get points */
4659: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4660: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4661: /* Get array */
4662: VecGetArray(v, &array);
4663: /* Get values */
4664: for (f = 0; f < numFields; ++f) {
4665: const PetscInt **perms = NULL;
4666: const PetscScalar **flips = NULL;
4668: if (!fieldActive[f]) {
4669: for (p = 0; p < numPoints*2; p += 2) {
4670: PetscInt fdof;
4671: PetscSectionGetFieldDof(section, points[p], f, &fdof);
4672: offset += fdof;
4673: }
4674: continue;
4675: }
4676: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4677: switch (mode) {
4678: case INSERT_VALUES:
4679: for (p = 0; p < numPoints; p++) {
4680: const PetscInt point = points[2*p];
4681: const PetscInt *perm = perms ? perms[p] : NULL;
4682: const PetscScalar *flip = flips ? flips[p] : NULL;
4683: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4684: } break;
4685: case INSERT_ALL_VALUES:
4686: for (p = 0; p < numPoints; p++) {
4687: const PetscInt point = points[2*p];
4688: const PetscInt *perm = perms ? perms[p] : NULL;
4689: const PetscScalar *flip = flips ? flips[p] : NULL;
4690: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4691: } break;
4692: case INSERT_BC_VALUES:
4693: for (p = 0; p < numPoints; p++) {
4694: const PetscInt point = points[2*p];
4695: const PetscInt *perm = perms ? perms[p] : NULL;
4696: const PetscScalar *flip = flips ? flips[p] : NULL;
4697: updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4698: } break;
4699: case ADD_VALUES:
4700: for (p = 0; p < numPoints; p++) {
4701: const PetscInt point = points[2*p];
4702: const PetscInt *perm = perms ? perms[p] : NULL;
4703: const PetscScalar *flip = flips ? flips[p] : NULL;
4704: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4705: } break;
4706: case ADD_ALL_VALUES:
4707: for (p = 0; p < numPoints; p++) {
4708: const PetscInt point = points[2*p];
4709: const PetscInt *perm = perms ? perms[p] : NULL;
4710: const PetscScalar *flip = flips ? flips[p] : NULL;
4711: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4712: } break;
4713: default:
4714: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4715: }
4716: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4717: }
4718: /* Cleanup points */
4719: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4720: /* Cleanup array */
4721: VecRestoreArray(v, &array);
4722: return(0);
4723: }
4725: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4726: {
4727: PetscMPIInt rank;
4728: PetscInt i, j;
4732: MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4733: PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4734: for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4735: for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4736: numCIndices = numCIndices ? numCIndices : numRIndices;
4737: for (i = 0; i < numRIndices; i++) {
4738: PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4739: for (j = 0; j < numCIndices; j++) {
4740: #if defined(PETSC_USE_COMPLEX)
4741: PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4742: #else
4743: PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4744: #endif
4745: }
4746: PetscViewerASCIIPrintf(viewer, "\n");
4747: }
4748: return(0);
4749: }
4751: /* . off - The global offset of this point */
4752: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4753: {
4754: PetscInt dof; /* The number of unknowns on this point */
4755: PetscInt cdof; /* The number of constraints on this point */
4756: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4757: PetscInt cind = 0, k;
4758: PetscErrorCode ierr;
4761: PetscSectionGetDof(section, point, &dof);
4762: PetscSectionGetConstraintDof(section, point, &cdof);
4763: if (!cdof || setBC) {
4764: if (perm) {
4765: for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4766: } else {
4767: for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4768: }
4769: } else {
4770: PetscSectionGetConstraintIndices(section, point, &cdofs);
4771: if (perm) {
4772: for (k = 0; k < dof; ++k) {
4773: if ((cind < cdof) && (k == cdofs[cind])) {
4774: /* Insert check for returning constrained indices */
4775: indices[*loff+perm[k]] = -(off+k+1);
4776: ++cind;
4777: } else {
4778: indices[*loff+perm[k]] = off+k-cind;
4779: }
4780: }
4781: } else {
4782: for (k = 0; k < dof; ++k) {
4783: if ((cind < cdof) && (k == cdofs[cind])) {
4784: /* Insert check for returning constrained indices */
4785: indices[*loff+k] = -(off+k+1);
4786: ++cind;
4787: } else {
4788: indices[*loff+k] = off+k-cind;
4789: }
4790: }
4791: }
4792: }
4793: *loff += dof;
4794: return(0);
4795: }
4797: /*
4798: This version only believes the point offset from the globalSection
4800: . off - The global offset of this point
4801: */
4802: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4803: {
4804: PetscInt numFields, foff, f;
4808: PetscSectionGetNumFields(section, &numFields);
4809: for (f = 0, foff = 0; f < numFields; ++f) {
4810: PetscInt fdof, cfdof;
4811: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4812: PetscInt cind = 0, b;
4813: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4815: PetscSectionGetFieldDof(section, point, f, &fdof);
4816: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4817: if (!cfdof || setBC) {
4818: if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4819: else {for (b = 0; b < fdof; b++) {indices[foffs[f]+ b ] = off+foff+b;}}
4820: } else {
4821: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4822: if (perm) {
4823: for (b = 0; b < fdof; b++) {
4824: if ((cind < cfdof) && (b == fcdofs[cind])) {
4825: indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4826: ++cind;
4827: } else {
4828: indices[foffs[f]+perm[b]] = off+foff+b-cind;
4829: }
4830: }
4831: } else {
4832: for (b = 0; b < fdof; b++) {
4833: if ((cind < cfdof) && (b == fcdofs[cind])) {
4834: indices[foffs[f]+b] = -(off+foff+b+1);
4835: ++cind;
4836: } else {
4837: indices[foffs[f]+b] = off+foff+b-cind;
4838: }
4839: }
4840: }
4841: }
4842: foff += (setBC ? fdof : (fdof - cfdof));
4843: foffs[f] += fdof;
4844: }
4845: return(0);
4846: }
4848: /*
4849: This version believes the globalSection offsets for each field, rather than just the point offset
4851: . foffs - The offset into 'indices' for each field, since it is segregated by field
4852: */
4853: PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4854: {
4855: PetscInt numFields, foff, f;
4859: PetscSectionGetNumFields(section, &numFields);
4860: for (f = 0; f < numFields; ++f) {
4861: PetscInt fdof, cfdof;
4862: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4863: PetscInt cind = 0, b;
4864: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4866: PetscSectionGetFieldDof(section, point, f, &fdof);
4867: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4868: PetscSectionGetFieldOffset(globalSection, point, f, &foff);
4869: if (!cfdof || setBC) {
4870: if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = foff+b;}}
4871: else {for (b = 0; b < fdof; b++) {indices[foffs[f]+ b ] = foff+b;}}
4872: } else {
4873: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4874: if (perm) {
4875: for (b = 0; b < fdof; b++) {
4876: if ((cind < cfdof) && (b == fcdofs[cind])) {
4877: indices[foffs[f]+perm[b]] = -(foff+b+1);
4878: ++cind;
4879: } else {
4880: indices[foffs[f]+perm[b]] = foff+b-cind;
4881: }
4882: }
4883: } else {
4884: for (b = 0; b < fdof; b++) {
4885: if ((cind < cfdof) && (b == fcdofs[cind])) {
4886: indices[foffs[f]+b] = -(foff+b+1);
4887: ++cind;
4888: } else {
4889: indices[foffs[f]+b] = foff+b-cind;
4890: }
4891: }
4892: }
4893: }
4894: foffs[f] += fdof;
4895: }
4896: return(0);
4897: }
4899: 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)
4900: {
4901: Mat cMat;
4902: PetscSection aSec, cSec;
4903: IS aIS;
4904: PetscInt aStart = -1, aEnd = -1;
4905: const PetscInt *anchors;
4906: PetscInt numFields, f, p, q, newP = 0;
4907: PetscInt newNumPoints = 0, newNumIndices = 0;
4908: PetscInt *newPoints, *indices, *newIndices;
4909: PetscInt maxAnchor, maxDof;
4910: PetscInt newOffsets[32];
4911: PetscInt *pointMatOffsets[32];
4912: PetscInt *newPointOffsets[32];
4913: PetscScalar *pointMat[32];
4914: PetscScalar *newValues=NULL,*tmpValues;
4915: PetscBool anyConstrained = PETSC_FALSE;
4916: PetscErrorCode ierr;
4921: PetscSectionGetNumFields(section, &numFields);
4923: DMPlexGetAnchors(dm,&aSec,&aIS);
4924: /* if there are point-to-point constraints */
4925: if (aSec) {
4926: PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4927: ISGetIndices(aIS,&anchors);
4928: PetscSectionGetChart(aSec,&aStart,&aEnd);
4929: /* figure out how many points are going to be in the new element matrix
4930: * (we allow double counting, because it's all just going to be summed
4931: * into the global matrix anyway) */
4932: for (p = 0; p < 2*numPoints; p+=2) {
4933: PetscInt b = points[p];
4934: PetscInt bDof = 0, bSecDof;
4936: PetscSectionGetDof(section,b,&bSecDof);
4937: if (!bSecDof) {
4938: continue;
4939: }
4940: if (b >= aStart && b < aEnd) {
4941: PetscSectionGetDof(aSec,b,&bDof);
4942: }
4943: if (bDof) {
4944: /* this point is constrained */
4945: /* it is going to be replaced by its anchors */
4946: PetscInt bOff, q;
4948: anyConstrained = PETSC_TRUE;
4949: newNumPoints += bDof;
4950: PetscSectionGetOffset(aSec,b,&bOff);
4951: for (q = 0; q < bDof; q++) {
4952: PetscInt a = anchors[bOff + q];
4953: PetscInt aDof;
4955: PetscSectionGetDof(section,a,&aDof);
4956: newNumIndices += aDof;
4957: for (f = 0; f < numFields; ++f) {
4958: PetscInt fDof;
4960: PetscSectionGetFieldDof(section, a, f, &fDof);
4961: newOffsets[f+1] += fDof;
4962: }
4963: }
4964: }
4965: else {
4966: /* this point is not constrained */
4967: newNumPoints++;
4968: newNumIndices += bSecDof;
4969: for (f = 0; f < numFields; ++f) {
4970: PetscInt fDof;
4972: PetscSectionGetFieldDof(section, b, f, &fDof);
4973: newOffsets[f+1] += fDof;
4974: }
4975: }
4976: }
4977: }
4978: if (!anyConstrained) {
4979: if (outNumPoints) *outNumPoints = 0;
4980: if (outNumIndices) *outNumIndices = 0;
4981: if (outPoints) *outPoints = NULL;
4982: if (outValues) *outValues = NULL;
4983: if (aSec) {ISRestoreIndices(aIS,&anchors);}
4984: return(0);
4985: }
4987: if (outNumPoints) *outNumPoints = newNumPoints;
4988: if (outNumIndices) *outNumIndices = newNumIndices;
4990: for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
4992: if (!outPoints && !outValues) {
4993: if (offsets) {
4994: for (f = 0; f <= numFields; f++) {
4995: offsets[f] = newOffsets[f];
4996: }
4997: }
4998: if (aSec) {ISRestoreIndices(aIS,&anchors);}
4999: return(0);
5000: }
5002: if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
5004: DMGetDefaultConstraints(dm, &cSec, &cMat);
5006: /* workspaces */
5007: if (numFields) {
5008: for (f = 0; f < numFields; f++) {
5009: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5010: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5011: }
5012: }
5013: else {
5014: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5015: DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5016: }
5018: /* get workspaces for the point-to-point matrices */
5019: if (numFields) {
5020: PetscInt totalOffset, totalMatOffset;
5022: for (p = 0; p < numPoints; p++) {
5023: PetscInt b = points[2*p];
5024: PetscInt bDof = 0, bSecDof;
5026: PetscSectionGetDof(section,b,&bSecDof);
5027: if (!bSecDof) {
5028: for (f = 0; f < numFields; f++) {
5029: newPointOffsets[f][p + 1] = 0;
5030: pointMatOffsets[f][p + 1] = 0;
5031: }
5032: continue;
5033: }
5034: if (b >= aStart && b < aEnd) {
5035: PetscSectionGetDof(aSec, b, &bDof);
5036: }
5037: if (bDof) {
5038: for (f = 0; f < numFields; f++) {
5039: PetscInt fDof, q, bOff, allFDof = 0;
5041: PetscSectionGetFieldDof(section, b, f, &fDof);
5042: PetscSectionGetOffset(aSec, b, &bOff);
5043: for (q = 0; q < bDof; q++) {
5044: PetscInt a = anchors[bOff + q];
5045: PetscInt aFDof;
5047: PetscSectionGetFieldDof(section, a, f, &aFDof);
5048: allFDof += aFDof;
5049: }
5050: newPointOffsets[f][p+1] = allFDof;
5051: pointMatOffsets[f][p+1] = fDof * allFDof;
5052: }
5053: }
5054: else {
5055: for (f = 0; f < numFields; f++) {
5056: PetscInt fDof;
5058: PetscSectionGetFieldDof(section, b, f, &fDof);
5059: newPointOffsets[f][p+1] = fDof;
5060: pointMatOffsets[f][p+1] = 0;
5061: }
5062: }
5063: }
5064: for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5065: newPointOffsets[f][0] = totalOffset;
5066: pointMatOffsets[f][0] = totalMatOffset;
5067: for (p = 0; p < numPoints; p++) {
5068: newPointOffsets[f][p+1] += newPointOffsets[f][p];
5069: pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5070: }
5071: totalOffset = newPointOffsets[f][numPoints];
5072: totalMatOffset = pointMatOffsets[f][numPoints];
5073: DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5074: }
5075: }
5076: else {
5077: for (p = 0; p < numPoints; p++) {
5078: PetscInt b = points[2*p];
5079: PetscInt bDof = 0, bSecDof;
5081: PetscSectionGetDof(section,b,&bSecDof);
5082: if (!bSecDof) {
5083: newPointOffsets[0][p + 1] = 0;
5084: pointMatOffsets[0][p + 1] = 0;
5085: continue;
5086: }
5087: if (b >= aStart && b < aEnd) {
5088: PetscSectionGetDof(aSec, b, &bDof);
5089: }
5090: if (bDof) {
5091: PetscInt bOff, q, allDof = 0;
5093: PetscSectionGetOffset(aSec, b, &bOff);
5094: for (q = 0; q < bDof; q++) {
5095: PetscInt a = anchors[bOff + q], aDof;
5097: PetscSectionGetDof(section, a, &aDof);
5098: allDof += aDof;
5099: }
5100: newPointOffsets[0][p+1] = allDof;
5101: pointMatOffsets[0][p+1] = bSecDof * allDof;
5102: }
5103: else {
5104: newPointOffsets[0][p+1] = bSecDof;
5105: pointMatOffsets[0][p+1] = 0;
5106: }
5107: }
5108: newPointOffsets[0][0] = 0;
5109: pointMatOffsets[0][0] = 0;
5110: for (p = 0; p < numPoints; p++) {
5111: newPointOffsets[0][p+1] += newPointOffsets[0][p];
5112: pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5113: }
5114: DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5115: }
5117: /* output arrays */
5118: DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5120: /* get the point-to-point matrices; construct newPoints */
5121: PetscSectionGetMaxDof(aSec, &maxAnchor);
5122: PetscSectionGetMaxDof(section, &maxDof);
5123: DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5124: DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5125: if (numFields) {
5126: for (p = 0, newP = 0; p < numPoints; p++) {
5127: PetscInt b = points[2*p];
5128: PetscInt o = points[2*p+1];
5129: PetscInt bDof = 0, bSecDof;
5131: PetscSectionGetDof(section, b, &bSecDof);
5132: if (!bSecDof) {
5133: continue;
5134: }
5135: if (b >= aStart && b < aEnd) {
5136: PetscSectionGetDof(aSec, b, &bDof);
5137: }
5138: if (bDof) {
5139: PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5141: fStart[0] = 0;
5142: fEnd[0] = 0;
5143: for (f = 0; f < numFields; f++) {
5144: PetscInt fDof;
5146: PetscSectionGetFieldDof(cSec, b, f, &fDof);
5147: fStart[f+1] = fStart[f] + fDof;
5148: fEnd[f+1] = fStart[f+1];
5149: }
5150: PetscSectionGetOffset(cSec, b, &bOff);
5151: DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);
5153: fAnchorStart[0] = 0;
5154: fAnchorEnd[0] = 0;
5155: for (f = 0; f < numFields; f++) {
5156: PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5158: fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5159: fAnchorEnd[f+1] = fAnchorStart[f + 1];
5160: }
5161: PetscSectionGetOffset(aSec, b, &bOff);
5162: for (q = 0; q < bDof; q++) {
5163: PetscInt a = anchors[bOff + q], aOff;
5165: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5166: newPoints[2*(newP + q)] = a;
5167: newPoints[2*(newP + q) + 1] = 0;
5168: PetscSectionGetOffset(section, a, &aOff);
5169: DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5170: }
5171: newP += bDof;
5173: if (outValues) {
5174: /* get the point-to-point submatrix */
5175: for (f = 0; f < numFields; f++) {
5176: MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5177: }
5178: }
5179: }
5180: else {
5181: newPoints[2 * newP] = b;
5182: newPoints[2 * newP + 1] = o;
5183: newP++;
5184: }
5185: }
5186: } else {
5187: for (p = 0; p < numPoints; p++) {
5188: PetscInt b = points[2*p];
5189: PetscInt o = points[2*p+1];
5190: PetscInt bDof = 0, bSecDof;
5192: PetscSectionGetDof(section, b, &bSecDof);
5193: if (!bSecDof) {
5194: continue;
5195: }
5196: if (b >= aStart && b < aEnd) {
5197: PetscSectionGetDof(aSec, b, &bDof);
5198: }
5199: if (bDof) {
5200: PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5202: PetscSectionGetOffset(cSec, b, &bOff);
5203: DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);
5205: PetscSectionGetOffset (aSec, b, &bOff);
5206: for (q = 0; q < bDof; q++) {
5207: PetscInt a = anchors[bOff + q], aOff;
5209: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5211: newPoints[2*(newP + q)] = a;
5212: newPoints[2*(newP + q) + 1] = 0;
5213: PetscSectionGetOffset(section, a, &aOff);
5214: DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5215: }
5216: newP += bDof;
5218: /* get the point-to-point submatrix */
5219: if (outValues) {
5220: MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5221: }
5222: }
5223: else {
5224: newPoints[2 * newP] = b;
5225: newPoints[2 * newP + 1] = o;
5226: newP++;
5227: }
5228: }
5229: }
5231: if (outValues) {
5232: DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5233: PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5234: /* multiply constraints on the right */
5235: if (numFields) {
5236: for (f = 0; f < numFields; f++) {
5237: PetscInt oldOff = offsets[f];
5239: for (p = 0; p < numPoints; p++) {
5240: PetscInt cStart = newPointOffsets[f][p];
5241: PetscInt b = points[2 * p];
5242: PetscInt c, r, k;
5243: PetscInt dof;
5245: PetscSectionGetFieldDof(section,b,f,&dof);
5246: if (!dof) {
5247: continue;
5248: }
5249: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5250: PetscInt nCols = newPointOffsets[f][p+1]-cStart;
5251: const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5253: for (r = 0; r < numIndices; r++) {
5254: for (c = 0; c < nCols; c++) {
5255: for (k = 0; k < dof; k++) {
5256: tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5257: }
5258: }
5259: }
5260: }
5261: else {
5262: /* copy this column as is */
5263: for (r = 0; r < numIndices; r++) {
5264: for (c = 0; c < dof; c++) {
5265: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5266: }
5267: }
5268: }
5269: oldOff += dof;
5270: }
5271: }
5272: }
5273: else {
5274: PetscInt oldOff = 0;
5275: for (p = 0; p < numPoints; p++) {
5276: PetscInt cStart = newPointOffsets[0][p];
5277: PetscInt b = points[2 * p];
5278: PetscInt c, r, k;
5279: PetscInt dof;
5281: PetscSectionGetDof(section,b,&dof);
5282: if (!dof) {
5283: continue;
5284: }
5285: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5286: PetscInt nCols = newPointOffsets[0][p+1]-cStart;
5287: const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5289: for (r = 0; r < numIndices; r++) {
5290: for (c = 0; c < nCols; c++) {
5291: for (k = 0; k < dof; k++) {
5292: tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5293: }
5294: }
5295: }
5296: }
5297: else {
5298: /* copy this column as is */
5299: for (r = 0; r < numIndices; r++) {
5300: for (c = 0; c < dof; c++) {
5301: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5302: }
5303: }
5304: }
5305: oldOff += dof;
5306: }
5307: }
5309: if (multiplyLeft) {
5310: DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5311: PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5312: /* multiply constraints transpose on the left */
5313: if (numFields) {
5314: for (f = 0; f < numFields; f++) {
5315: PetscInt oldOff = offsets[f];
5317: for (p = 0; p < numPoints; p++) {
5318: PetscInt rStart = newPointOffsets[f][p];
5319: PetscInt b = points[2 * p];
5320: PetscInt c, r, k;
5321: PetscInt dof;
5323: PetscSectionGetFieldDof(section,b,f,&dof);
5324: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5325: PetscInt nRows = newPointOffsets[f][p+1]-rStart;
5326: const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5328: for (r = 0; r < nRows; r++) {
5329: for (c = 0; c < newNumIndices; c++) {
5330: for (k = 0; k < dof; k++) {
5331: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5332: }
5333: }
5334: }
5335: }
5336: else {
5337: /* copy this row as is */
5338: for (r = 0; r < dof; r++) {
5339: for (c = 0; c < newNumIndices; c++) {
5340: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5341: }
5342: }
5343: }
5344: oldOff += dof;
5345: }
5346: }
5347: }
5348: else {
5349: PetscInt oldOff = 0;
5351: for (p = 0; p < numPoints; p++) {
5352: PetscInt rStart = newPointOffsets[0][p];
5353: PetscInt b = points[2 * p];
5354: PetscInt c, r, k;
5355: PetscInt dof;
5357: PetscSectionGetDof(section,b,&dof);
5358: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5359: PetscInt nRows = newPointOffsets[0][p+1]-rStart;
5360: const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5362: for (r = 0; r < nRows; r++) {
5363: for (c = 0; c < newNumIndices; c++) {
5364: for (k = 0; k < dof; k++) {
5365: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5366: }
5367: }
5368: }
5369: }
5370: else {
5371: /* copy this row as is */
5372: for (r = 0; r < dof; r++) {
5373: for (c = 0; c < newNumIndices; c++) {
5374: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5375: }
5376: }
5377: }
5378: oldOff += dof;
5379: }
5380: }
5382: DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5383: }
5384: else {
5385: newValues = tmpValues;
5386: }
5387: }
5389: /* clean up */
5390: DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5391: DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5393: if (numFields) {
5394: for (f = 0; f < numFields; f++) {
5395: DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5396: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5397: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5398: }
5399: }
5400: else {
5401: DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5402: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5403: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5404: }
5405: ISRestoreIndices(aIS,&anchors);
5407: /* output */
5408: if (outPoints) {
5409: *outPoints = newPoints;
5410: }
5411: else {
5412: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5413: }
5414: if (outValues) {
5415: *outValues = newValues;
5416: }
5417: for (f = 0; f <= numFields; f++) {
5418: offsets[f] = newOffsets[f];
5419: }
5420: return(0);
5421: }
5423: /*@C
5424: DMPlexGetClosureIndices - Get the global indices in a vector v for all points in the closure of the given point
5426: Not collective
5428: Input Parameters:
5429: + dm - The DM
5430: . section - The section describing the layout in v, or NULL to use the default section
5431: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5432: - point - The mesh point
5434: Output parameters:
5435: + numIndices - The number of indices
5436: . indices - The indices
5437: - outOffsets - Field offset if not NULL
5439: Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5441: Level: advanced
5443: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5444: @*/
5445: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5446: {
5447: PetscSection clSection;
5448: IS clPoints;
5449: const PetscInt *clp;
5450: const PetscInt **perms[32] = {NULL};
5451: PetscInt *points = NULL, *pointsNew;
5452: PetscInt numPoints, numPointsNew;
5453: PetscInt offsets[32];
5454: PetscInt Nf, Nind, NindNew, off, globalOff, f, p;
5455: PetscErrorCode ierr;
5463: PetscSectionGetNumFields(section, &Nf);
5464: if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5465: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5466: /* Get points in closure */
5467: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5468: /* Get number of indices and indices per field */
5469: for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5470: PetscInt dof, fdof;
5472: PetscSectionGetDof(section, points[p], &dof);
5473: for (f = 0; f < Nf; ++f) {
5474: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5475: offsets[f+1] += fdof;
5476: }
5477: Nind += dof;
5478: }
5479: for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5480: if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5481: if (!Nf) offsets[1] = Nind;
5482: /* Get dual space symmetries */
5483: for (f = 0; f < PetscMax(1,Nf); f++) {
5484: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5485: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5486: }
5487: /* Correct for hanging node constraints */
5488: {
5489: DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5490: if (numPointsNew) {
5491: for (f = 0; f < PetscMax(1,Nf); f++) {
5492: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5493: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5494: }
5495: for (f = 0; f < PetscMax(1,Nf); f++) {
5496: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5497: else {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5498: }
5499: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5500: numPoints = numPointsNew;
5501: Nind = NindNew;
5502: points = pointsNew;
5503: }
5504: }
5505: /* Calculate indices */
5506: DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5507: if (Nf) {
5508: if (outOffsets) {
5509: PetscInt f;
5511: for (f = 0; f <= Nf; f++) {
5512: outOffsets[f] = offsets[f];
5513: }
5514: }
5515: for (p = 0; p < numPoints; p++) {
5516: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5517: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5518: }
5519: } else {
5520: for (p = 0, off = 0; p < numPoints; p++) {
5521: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5523: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5524: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5525: }
5526: }
5527: /* Cleanup points */
5528: for (f = 0; f < PetscMax(1,Nf); f++) {
5529: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5530: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5531: }
5532: if (numPointsNew) {
5533: DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5534: } else {
5535: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5536: }
5537: if (numIndices) *numIndices = Nind;
5538: return(0);
5539: }
5541: /*@C
5542: DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5544: Not collective
5546: Input Parameters:
5547: + dm - The DM
5548: . section - The section describing the layout in v, or NULL to use the default section
5549: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5550: . point - The mesh point
5551: . numIndices - The number of indices
5552: . indices - The indices
5553: - outOffsets - Field offset if not NULL
5555: Level: advanced
5557: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5558: @*/
5559: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5560: {
5566: DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5567: return(0);
5568: }
5570: /*@C
5571: DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5573: Not collective
5575: Input Parameters:
5576: + dm - The DM
5577: . section - The section describing the layout in v, or NULL to use the default section
5578: . globalSection - The section describing the layout in v, or NULL to use the default global section
5579: . A - The matrix
5580: . point - The point in the DM
5581: . values - The array of values
5582: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5584: Fortran Notes:
5585: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5587: Level: intermediate
5589: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5590: @*/
5591: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5592: {
5593: DM_Plex *mesh = (DM_Plex*) dm->data;
5594: PetscSection clSection;
5595: IS clPoints;
5596: PetscInt *points = NULL, *newPoints;
5597: const PetscInt *clp;
5598: PetscInt *indices;
5599: PetscInt offsets[32];
5600: const PetscInt **perms[32] = {NULL};
5601: const PetscScalar **flips[32] = {NULL};
5602: PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5603: PetscScalar *valCopy = NULL;
5604: PetscScalar *newValues;
5605: PetscErrorCode ierr;
5609: if (!section) {DMGetSection(dm, §ion);}
5611: if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5614: PetscSectionGetNumFields(section, &numFields);
5615: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5616: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5617: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5618: for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5619: PetscInt fdof;
5621: PetscSectionGetDof(section, points[p], &dof);
5622: for (f = 0; f < numFields; ++f) {
5623: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5624: offsets[f+1] += fdof;
5625: }
5626: numIndices += dof;
5627: }
5628: for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5630: if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5631: /* Get symmetries */
5632: for (f = 0; f < PetscMax(1,numFields); f++) {
5633: if (numFields) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5634: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5635: if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5636: PetscInt foffset = offsets[f];
5638: for (p = 0; p < numPoints; p++) {
5639: PetscInt point = points[2*p], fdof;
5640: const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5642: if (!numFields) {
5643: PetscSectionGetDof(section,point,&fdof);
5644: } else {
5645: PetscSectionGetFieldDof(section,point,f,&fdof);
5646: }
5647: if (flip) {
5648: PetscInt i, j, k;
5650: if (!valCopy) {
5651: DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5652: for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5653: values = valCopy;
5654: }
5655: for (i = 0; i < fdof; i++) {
5656: PetscScalar fval = flip[i];
5658: for (k = 0; k < numIndices; k++) {
5659: valCopy[numIndices * (foffset + i) + k] *= fval;
5660: valCopy[numIndices * k + (foffset + i)] *= fval;
5661: }
5662: }
5663: }
5664: foffset += fdof;
5665: }
5666: }
5667: }
5668: DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5669: if (newNumPoints) {
5670: if (valCopy) {
5671: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5672: }
5673: for (f = 0; f < PetscMax(1,numFields); f++) {
5674: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5675: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5676: }
5677: for (f = 0; f < PetscMax(1,numFields); f++) {
5678: if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5679: else {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5680: }
5681: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5682: numPoints = newNumPoints;
5683: numIndices = newNumIndices;
5684: points = newPoints;
5685: values = newValues;
5686: }
5687: DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5688: if (numFields) {
5689: PetscBool useFieldOffsets;
5691: PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
5692: if (useFieldOffsets) {
5693: for (p = 0; p < numPoints; p++) {
5694: DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, indices);
5695: }
5696: } else {
5697: for (p = 0; p < numPoints; p++) {
5698: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5699: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5700: }
5701: }
5702: } else {
5703: for (p = 0, off = 0; p < numPoints; p++) {
5704: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5705: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5706: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5707: }
5708: }
5709: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5710: MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5711: if (mesh->printFEM > 1) {
5712: PetscInt i;
5713: PetscPrintf(PETSC_COMM_SELF, " Indices:");
5714: for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5715: PetscPrintf(PETSC_COMM_SELF, "\n");
5716: }
5717: if (ierr) {
5718: PetscMPIInt rank;
5719: PetscErrorCode ierr2;
5721: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5722: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5723: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5724: ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5725:
5726: }
5727: for (f = 0; f < PetscMax(1,numFields); f++) {
5728: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5729: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5730: }
5731: if (newNumPoints) {
5732: DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5733: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5734: }
5735: else {
5736: if (valCopy) {
5737: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5738: }
5739: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5740: }
5741: DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5742: return(0);
5743: }
5745: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5746: {
5747: DM_Plex *mesh = (DM_Plex*) dmf->data;
5748: PetscInt *fpoints = NULL, *ftotpoints = NULL;
5749: PetscInt *cpoints = NULL;
5750: PetscInt *findices, *cindices;
5751: PetscInt foffsets[32], coffsets[32];
5752: CellRefiner cellRefiner;
5753: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5754: PetscErrorCode ierr;
5759: if (!fsection) {DMGetSection(dmf, &fsection);}
5761: if (!csection) {DMGetSection(dmc, &csection);}
5763: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
5765: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
5768: PetscSectionGetNumFields(fsection, &numFields);
5769: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5770: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5771: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5772: /* Column indices */
5773: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5774: maxFPoints = numCPoints;
5775: /* Compress out points not in the section */
5776: /* TODO: Squeeze out points with 0 dof as well */
5777: PetscSectionGetChart(csection, &pStart, &pEnd);
5778: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5779: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5780: cpoints[q*2] = cpoints[p];
5781: cpoints[q*2+1] = cpoints[p+1];
5782: ++q;
5783: }
5784: }
5785: numCPoints = q;
5786: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5787: PetscInt fdof;
5789: PetscSectionGetDof(csection, cpoints[p], &dof);
5790: if (!dof) continue;
5791: for (f = 0; f < numFields; ++f) {
5792: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5793: coffsets[f+1] += fdof;
5794: }
5795: numCIndices += dof;
5796: }
5797: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5798: /* Row indices */
5799: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5800: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5801: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5802: for (r = 0, q = 0; r < numSubcells; ++r) {
5803: /* TODO Map from coarse to fine cells */
5804: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5805: /* Compress out points not in the section */
5806: PetscSectionGetChart(fsection, &pStart, &pEnd);
5807: for (p = 0; p < numFPoints*2; p += 2) {
5808: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5809: PetscSectionGetDof(fsection, fpoints[p], &dof);
5810: if (!dof) continue;
5811: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5812: if (s < q) continue;
5813: ftotpoints[q*2] = fpoints[p];
5814: ftotpoints[q*2+1] = fpoints[p+1];
5815: ++q;
5816: }
5817: }
5818: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5819: }
5820: numFPoints = q;
5821: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5822: PetscInt fdof;
5824: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5825: if (!dof) continue;
5826: for (f = 0; f < numFields; ++f) {
5827: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5828: foffsets[f+1] += fdof;
5829: }
5830: numFIndices += dof;
5831: }
5832: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5834: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5835: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5836: DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5837: DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5838: if (numFields) {
5839: const PetscInt **permsF[32] = {NULL};
5840: const PetscInt **permsC[32] = {NULL};
5842: for (f = 0; f < numFields; f++) {
5843: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5844: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5845: }
5846: for (p = 0; p < numFPoints; p++) {
5847: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5848: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5849: }
5850: for (p = 0; p < numCPoints; p++) {
5851: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5852: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5853: }
5854: for (f = 0; f < numFields; f++) {
5855: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5856: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5857: }
5858: } else {
5859: const PetscInt **permsF = NULL;
5860: const PetscInt **permsC = NULL;
5862: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5863: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5864: for (p = 0, off = 0; p < numFPoints; p++) {
5865: const PetscInt *perm = permsF ? permsF[p] : NULL;
5867: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5868: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5869: }
5870: for (p = 0, off = 0; p < numCPoints; p++) {
5871: const PetscInt *perm = permsC ? permsC[p] : NULL;
5873: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5874: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5875: }
5876: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5877: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5878: }
5879: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5880: /* TODO: flips */
5881: MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5882: if (ierr) {
5883: PetscMPIInt rank;
5884: PetscErrorCode ierr2;
5886: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5887: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5888: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5889: ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
5890: ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
5891:
5892: }
5893: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
5894: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5895: DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5896: DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5897: return(0);
5898: }
5900: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5901: {
5902: PetscInt *fpoints = NULL, *ftotpoints = NULL;
5903: PetscInt *cpoints = NULL;
5904: PetscInt foffsets[32], coffsets[32];
5905: CellRefiner cellRefiner;
5906: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5912: if (!fsection) {DMGetSection(dmf, &fsection);}
5914: if (!csection) {DMGetSection(dmc, &csection);}
5916: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
5918: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
5920: PetscSectionGetNumFields(fsection, &numFields);
5921: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5922: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5923: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5924: /* Column indices */
5925: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5926: maxFPoints = numCPoints;
5927: /* Compress out points not in the section */
5928: /* TODO: Squeeze out points with 0 dof as well */
5929: PetscSectionGetChart(csection, &pStart, &pEnd);
5930: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5931: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5932: cpoints[q*2] = cpoints[p];
5933: cpoints[q*2+1] = cpoints[p+1];
5934: ++q;
5935: }
5936: }
5937: numCPoints = q;
5938: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5939: PetscInt fdof;
5941: PetscSectionGetDof(csection, cpoints[p], &dof);
5942: if (!dof) continue;
5943: for (f = 0; f < numFields; ++f) {
5944: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5945: coffsets[f+1] += fdof;
5946: }
5947: numCIndices += dof;
5948: }
5949: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5950: /* Row indices */
5951: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5952: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5953: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5954: for (r = 0, q = 0; r < numSubcells; ++r) {
5955: /* TODO Map from coarse to fine cells */
5956: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5957: /* Compress out points not in the section */
5958: PetscSectionGetChart(fsection, &pStart, &pEnd);
5959: for (p = 0; p < numFPoints*2; p += 2) {
5960: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5961: PetscSectionGetDof(fsection, fpoints[p], &dof);
5962: if (!dof) continue;
5963: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5964: if (s < q) continue;
5965: ftotpoints[q*2] = fpoints[p];
5966: ftotpoints[q*2+1] = fpoints[p+1];
5967: ++q;
5968: }
5969: }
5970: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5971: }
5972: numFPoints = q;
5973: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5974: PetscInt fdof;
5976: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5977: if (!dof) continue;
5978: for (f = 0; f < numFields; ++f) {
5979: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5980: foffsets[f+1] += fdof;
5981: }
5982: numFIndices += dof;
5983: }
5984: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5986: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5987: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5988: if (numFields) {
5989: const PetscInt **permsF[32] = {NULL};
5990: const PetscInt **permsC[32] = {NULL};
5992: for (f = 0; f < numFields; f++) {
5993: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5994: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5995: }
5996: for (p = 0; p < numFPoints; p++) {
5997: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5998: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5999: }
6000: for (p = 0; p < numCPoints; p++) {
6001: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6002: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6003: }
6004: for (f = 0; f < numFields; f++) {
6005: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6006: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6007: }
6008: } else {
6009: const PetscInt **permsF = NULL;
6010: const PetscInt **permsC = NULL;
6012: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6013: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6014: for (p = 0, off = 0; p < numFPoints; p++) {
6015: const PetscInt *perm = permsF ? permsF[p] : NULL;
6017: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6018: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6019: }
6020: for (p = 0, off = 0; p < numCPoints; p++) {
6021: const PetscInt *perm = permsC ? permsC[p] : NULL;
6023: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6024: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6025: }
6026: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6027: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6028: }
6029: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6030: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6031: return(0);
6032: }
6034: /*@
6035: DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6037: Input Parameter:
6038: . dm - The DMPlex object
6040: Output Parameters:
6041: + cMax - The first hybrid cell
6042: . fMax - The first hybrid face
6043: . eMax - The first hybrid edge
6044: - vMax - The first hybrid vertex
6046: Level: developer
6048: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6049: @*/
6050: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6051: {
6052: DM_Plex *mesh = (DM_Plex*) dm->data;
6053: PetscInt dim;
6058: DMGetDimension(dm, &dim);
6059: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6060: if (cMax) *cMax = mesh->hybridPointMax[dim];
6061: if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6062: if (eMax) *eMax = mesh->hybridPointMax[1];
6063: if (vMax) *vMax = mesh->hybridPointMax[0];
6064: return(0);
6065: }
6067: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6068: {
6069: IS is, his;
6070: PetscInt first = 0, stride;
6071: PetscBool isStride;
6075: DMLabelGetStratumIS(depthLabel, d, &is);
6076: PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6077: if (isStride) {
6078: ISStrideGetInfo(is, &first, &stride);
6079: }
6080: if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6081: ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6082: DMLabelSetStratumIS(dimLabel, d, his);
6083: ISDestroy(&his);
6084: ISDestroy(&is);
6085: return(0);
6086: }
6088: /*@
6089: DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6091: Input Parameters:
6092: . dm - The DMPlex object
6093: . cMax - The first hybrid cell
6094: . fMax - The first hybrid face
6095: . eMax - The first hybrid edge
6096: - vMax - The first hybrid vertex
6098: Level: developer
6100: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6101: @*/
6102: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6103: {
6104: DM_Plex *mesh = (DM_Plex*) dm->data;
6105: PetscInt dim;
6110: DMGetDimension(dm, &dim);
6111: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6112: if (cMax >= 0) mesh->hybridPointMax[dim] = cMax;
6113: if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6114: if (eMax >= 0) mesh->hybridPointMax[1] = eMax;
6115: if (vMax >= 0) mesh->hybridPointMax[0] = vMax;
6116: return(0);
6117: }
6119: /*@C
6120: DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6122: Input Parameter:
6123: . dm - The DMPlex object
6125: Output Parameter:
6126: . cellHeight - The height of a cell
6128: Level: developer
6130: .seealso DMPlexSetVTKCellHeight()
6131: @*/
6132: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6133: {
6134: DM_Plex *mesh = (DM_Plex*) dm->data;
6139: *cellHeight = mesh->vtkCellHeight;
6140: return(0);
6141: }
6143: /*@C
6144: DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6146: Input Parameters:
6147: + dm - The DMPlex object
6148: - cellHeight - The height of a cell
6150: Level: developer
6152: .seealso DMPlexGetVTKCellHeight()
6153: @*/
6154: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6155: {
6156: DM_Plex *mesh = (DM_Plex*) dm->data;
6160: mesh->vtkCellHeight = cellHeight;
6161: return(0);
6162: }
6164: /* We can easily have a form that takes an IS instead */
6165: PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6166: {
6167: PetscSection section, globalSection;
6168: PetscInt *numbers, p;
6172: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
6173: PetscSectionSetChart(section, pStart, pEnd);
6174: for (p = pStart; p < pEnd; ++p) {
6175: PetscSectionSetDof(section, p, 1);
6176: }
6177: PetscSectionSetUp(section);
6178: PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6179: PetscMalloc1(pEnd - pStart, &numbers);
6180: for (p = pStart; p < pEnd; ++p) {
6181: PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6182: if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6183: else numbers[p-pStart] += shift;
6184: }
6185: ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6186: if (globalSize) {
6187: PetscLayout layout;
6188: PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6189: PetscLayoutGetSize(layout, globalSize);
6190: PetscLayoutDestroy(&layout);
6191: }
6192: PetscSectionDestroy(§ion);
6193: PetscSectionDestroy(&globalSection);
6194: return(0);
6195: }
6197: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6198: {
6199: PetscInt cellHeight, cStart, cEnd, cMax;
6203: DMPlexGetVTKCellHeight(dm, &cellHeight);
6204: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6205: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6206: if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6207: DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6208: return(0);
6209: }
6211: /*@
6212: DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6214: Input Parameter:
6215: . dm - The DMPlex object
6217: Output Parameter:
6218: . globalCellNumbers - Global cell numbers for all cells on this process
6220: Level: developer
6222: .seealso DMPlexGetVertexNumbering()
6223: @*/
6224: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6225: {
6226: DM_Plex *mesh = (DM_Plex*) dm->data;
6231: if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6232: *globalCellNumbers = mesh->globalCellNumbers;
6233: return(0);
6234: }
6236: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6237: {
6238: PetscInt vStart, vEnd, vMax;
6243: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6244: DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6245: if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6246: DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6247: return(0);
6248: }
6250: /*@
6251: DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process
6253: Input Parameter:
6254: . dm - The DMPlex object
6256: Output Parameter:
6257: . globalVertexNumbers - Global vertex numbers for all vertices on this process
6259: Level: developer
6261: .seealso DMPlexGetCellNumbering()
6262: @*/
6263: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6264: {
6265: DM_Plex *mesh = (DM_Plex*) dm->data;
6270: if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6271: *globalVertexNumbers = mesh->globalVertexNumbers;
6272: return(0);
6273: }
6275: /*@
6276: DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6278: Input Parameter:
6279: . dm - The DMPlex object
6281: Output Parameter:
6282: . globalPointNumbers - Global numbers for all points on this process
6284: Level: developer
6286: .seealso DMPlexGetCellNumbering()
6287: @*/
6288: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6289: {
6290: IS nums[4];
6291: PetscInt depths[4], gdepths[4], starts[4];
6292: PetscInt depth, d, shift = 0;
6297: DMPlexGetDepth(dm, &depth);
6298: /* For unstratified meshes use dim instead of depth */
6299: if (depth < 0) {DMGetDimension(dm, &depth);}
6300: for (d = 0; d <= depth; ++d) {
6301: PetscInt end;
6303: depths[d] = depth-d;
6304: DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6305: if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6306: }
6307: PetscSortIntWithArray(depth+1, starts, depths);
6308: MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6309: for (d = 0; d <= depth; ++d) {
6310: if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6311: }
6312: for (d = 0; d <= depth; ++d) {
6313: PetscInt pStart, pEnd, gsize;
6315: DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6316: DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6317: shift += gsize;
6318: }
6319: ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6320: for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6321: return(0);
6322: }
6325: /*@
6326: DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6328: Input Parameter:
6329: . dm - The DMPlex object
6331: Output Parameter:
6332: . ranks - The rank field
6334: Options Database Keys:
6335: . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6337: Level: intermediate
6339: .seealso: DMView()
6340: @*/
6341: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6342: {
6343: DM rdm;
6344: PetscFE fe;
6345: PetscScalar *r;
6346: PetscMPIInt rank;
6347: PetscInt dim, cStart, cEnd, c;
6353: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6354: DMClone(dm, &rdm);
6355: DMGetDimension(rdm, &dim);
6356: PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6357: PetscObjectSetName((PetscObject) fe, "rank");
6358: DMSetField(rdm, 0, NULL, (PetscObject) fe);
6359: PetscFEDestroy(&fe);
6360: DMCreateDS(rdm);
6361: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6362: DMCreateGlobalVector(rdm, ranks);
6363: PetscObjectSetName((PetscObject) *ranks, "partition");
6364: VecGetArray(*ranks, &r);
6365: for (c = cStart; c < cEnd; ++c) {
6366: PetscScalar *lr;
6368: DMPlexPointGlobalRef(rdm, c, r, &lr);
6369: *lr = rank;
6370: }
6371: VecRestoreArray(*ranks, &r);
6372: DMDestroy(&rdm);
6373: return(0);
6374: }
6376: /*@
6377: DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
6379: Input Parameters:
6380: + dm - The DMPlex
6381: - label - The DMLabel
6383: Output Parameter:
6384: . val - The label value field
6386: Options Database Keys:
6387: . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
6389: Level: intermediate
6391: .seealso: DMView()
6392: @*/
6393: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6394: {
6395: DM rdm;
6396: PetscFE fe;
6397: PetscScalar *v;
6398: PetscInt dim, cStart, cEnd, c;
6405: DMClone(dm, &rdm);
6406: DMGetDimension(rdm, &dim);
6407: PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6408: PetscObjectSetName((PetscObject) fe, "label_value");
6409: DMSetField(rdm, 0, NULL, (PetscObject) fe);
6410: PetscFEDestroy(&fe);
6411: DMCreateDS(rdm);
6412: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6413: DMCreateGlobalVector(rdm, val);
6414: PetscObjectSetName((PetscObject) *val, "label_value");
6415: VecGetArray(*val, &v);
6416: for (c = cStart; c < cEnd; ++c) {
6417: PetscScalar *lv;
6418: PetscInt cval;
6420: DMPlexPointGlobalRef(rdm, c, v, &lv);
6421: DMLabelGetValue(label, c, &cval);
6422: *lv = cval;
6423: }
6424: VecRestoreArray(*val, &v);
6425: DMDestroy(&rdm);
6426: return(0);
6427: }
6429: /*@
6430: DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6432: Input Parameter:
6433: . dm - The DMPlex object
6435: Note: This is a useful diagnostic when creating meshes programmatically.
6437: Level: developer
6439: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6440: @*/
6441: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6442: {
6443: PetscSection coneSection, supportSection;
6444: const PetscInt *cone, *support;
6445: PetscInt coneSize, c, supportSize, s;
6446: PetscInt pStart, pEnd, p, pp, csize, ssize;
6447: PetscBool storagecheck = PETSC_TRUE;
6448: PetscErrorCode ierr;
6452: DMPlexGetConeSection(dm, &coneSection);
6453: DMPlexGetSupportSection(dm, &supportSection);
6454: /* Check that point p is found in the support of its cone points, and vice versa */
6455: DMPlexGetChart(dm, &pStart, &pEnd);
6456: for (p = pStart; p < pEnd; ++p) {
6457: DMPlexGetConeSize(dm, p, &coneSize);
6458: DMPlexGetCone(dm, p, &cone);
6459: for (c = 0; c < coneSize; ++c) {
6460: PetscBool dup = PETSC_FALSE;
6461: PetscInt d;
6462: for (d = c-1; d >= 0; --d) {
6463: if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6464: }
6465: DMPlexGetSupportSize(dm, cone[c], &supportSize);
6466: DMPlexGetSupport(dm, cone[c], &support);
6467: for (s = 0; s < supportSize; ++s) {
6468: if (support[s] == p) break;
6469: }
6470: if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6471: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6472: for (s = 0; s < coneSize; ++s) {
6473: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6474: }
6475: PetscPrintf(PETSC_COMM_SELF, "\n");
6476: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6477: for (s = 0; s < supportSize; ++s) {
6478: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6479: }
6480: PetscPrintf(PETSC_COMM_SELF, "\n");
6481: if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6482: else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6483: }
6484: }
6485: DMPlexGetTreeParent(dm, p, &pp, NULL);
6486: if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6487: DMPlexGetSupportSize(dm, p, &supportSize);
6488: DMPlexGetSupport(dm, p, &support);
6489: for (s = 0; s < supportSize; ++s) {
6490: DMPlexGetConeSize(dm, support[s], &coneSize);
6491: DMPlexGetCone(dm, support[s], &cone);
6492: for (c = 0; c < coneSize; ++c) {
6493: DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
6494: if (cone[c] != pp) { c = 0; break; }
6495: if (cone[c] == p) break;
6496: }
6497: if (c >= coneSize) {
6498: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6499: for (c = 0; c < supportSize; ++c) {
6500: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6501: }
6502: PetscPrintf(PETSC_COMM_SELF, "\n");
6503: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6504: for (c = 0; c < coneSize; ++c) {
6505: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6506: }
6507: PetscPrintf(PETSC_COMM_SELF, "\n");
6508: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6509: }
6510: }
6511: }
6512: if (storagecheck) {
6513: PetscSectionGetStorageSize(coneSection, &csize);
6514: PetscSectionGetStorageSize(supportSection, &ssize);
6515: if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6516: }
6517: return(0);
6518: }
6520: /*@
6521: DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6523: Input Parameters:
6524: + dm - The DMPlex object
6525: . isSimplex - Are the cells simplices or tensor products
6526: - cellHeight - Normally 0
6528: Note: This is a useful diagnostic when creating meshes programmatically.
6530: Level: developer
6532: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6533: @*/
6534: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6535: {
6536: PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6541: DMGetDimension(dm, &dim);
6542: switch (dim) {
6543: case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6544: case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6545: case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6546: default:
6547: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6548: }
6549: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6550: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6551: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6552: cMax = cMax >= 0 ? cMax : cEnd;
6553: for (c = cStart; c < cMax; ++c) {
6554: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6556: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6557: for (cl = 0; cl < closureSize*2; cl += 2) {
6558: const PetscInt p = closure[cl];
6559: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6560: }
6561: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6562: if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D", c, coneSize, numCorners);
6563: }
6564: for (c = cMax; c < cEnd; ++c) {
6565: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6567: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6568: for (cl = 0; cl < closureSize*2; cl += 2) {
6569: const PetscInt p = closure[cl];
6570: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6571: }
6572: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6573: if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has %D vertices > %D", c, coneSize, numHybridCorners);
6574: }
6575: return(0);
6576: }
6578: /*@
6579: DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6581: Input Parameters:
6582: + dm - The DMPlex object
6583: . isSimplex - Are the cells simplices or tensor products
6584: - cellHeight - Normally 0
6586: Note: This is a useful diagnostic when creating meshes programmatically.
6588: Level: developer
6590: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6591: @*/
6592: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6593: {
6594: PetscInt pMax[4];
6595: PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h;
6600: DMGetDimension(dm, &dim);
6601: DMPlexGetDepth(dm, &depth);
6602: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6603: DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6604: for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
6605: DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6606: for (c = cStart; c < cEnd; ++c) {
6607: const PetscInt *cone, *ornt, *faces;
6608: PetscInt numFaces, faceSize, coneSize,f;
6609: PetscInt *closure = NULL, closureSize, cl, numCorners = 0;
6611: if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6612: DMPlexGetConeSize(dm, c, &coneSize);
6613: DMPlexGetCone(dm, c, &cone);
6614: DMPlexGetConeOrientation(dm, c, &ornt);
6615: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6616: for (cl = 0; cl < closureSize*2; cl += 2) {
6617: const PetscInt p = closure[cl];
6618: if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6619: }
6620: DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6621: if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6622: for (f = 0; f < numFaces; ++f) {
6623: PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6625: DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6626: for (cl = 0; cl < fclosureSize*2; cl += 2) {
6627: const PetscInt p = fclosure[cl];
6628: if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6629: }
6630: 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);
6631: for (v = 0; v < fnumCorners; ++v) {
6632: 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]);
6633: }
6634: DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6635: }
6636: DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6637: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6638: }
6639: }
6640: return(0);
6641: }
6643: /*@
6644: DMPlexCheckGeometry - Check the geometry of mesh cells
6646: Input Parameter:
6647: . dm - The DMPlex object
6649: Note: This is a useful diagnostic when creating meshes programmatically.
6651: Level: developer
6653: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
6654: @*/
6655: PetscErrorCode DMPlexCheckGeometry(DM dm)
6656: {
6657: PetscReal detJ, J[9], refVol = 1.0;
6658: PetscReal vol;
6659: PetscInt dim, depth, d, cStart, cEnd, c;
6663: DMGetDimension(dm, &dim);
6664: DMPlexGetDepth(dm, &depth);
6665: for (d = 0; d < dim; ++d) refVol *= 2.0;
6666: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6667: for (c = cStart; c < cEnd; ++c) {
6668: DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
6669: if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
6670: PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
6671: if (depth > 1) {
6672: DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
6673: if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
6674: PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
6675: }
6676: }
6677: return(0);
6678: }
6680: static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
6681: {
6682: PetscInt i,l,n;
6683: const PetscInt *cone;
6687: *missingPoint = -1;
6688: DMPlexGetConeSize(dm, p, &n);
6689: DMPlexGetCone(dm, p, &cone);
6690: for (i=0; i<n; i++) {
6691: PetscFindInt(cone[i], npoints, points, &l);
6692: if (l < 0) {
6693: *missingPoint = cone[i];
6694: break;
6695: }
6696: }
6697: return(0);
6698: }
6700: /*@
6701: DMPlexCheckPointSF - Check that several sufficient conditions are met for the point SF of this plex.
6703: Input Parameters:
6704: . dm - The DMPlex object
6706: Note: This is mainly intended for debugging/testing purposes.
6708: Level: developer
6710: .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6711: @*/
6712: PetscErrorCode DMPlexCheckPointSF(DM dm)
6713: {
6714: PetscSF sf;
6715: PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
6716: const PetscInt *locals;
6721: DMPlexGetDepth(dm, &depth);
6722: DMGetPointSF(dm, &sf);
6723: PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);
6725: /* 1) check there are no faces in 2D, cells in 3D, in interface */
6726: DMPlexGetVTKCellHeight(dm, &d);
6727: DMPlexGetHeightStratum(dm, d, &plo, &phi);
6728: for (i=0; i<nleaves; i++) {
6729: p = locals[i];
6730: if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
6731: }
6733: /* 2) if some point is in interface, then all its cone points must be also in interface */
6734: for (i=0; i<nleaves; i++) {
6735: p = locals[i];
6736: DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);
6737: if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
6738: }
6739: return(0);
6740: }
6742: typedef struct cell_stats
6743: {
6744: PetscReal min, max, sum, squaresum;
6745: PetscInt count;
6746: } cell_stats_t;
6748: static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
6749: {
6750: PetscInt i, N = *len;
6752: for (i = 0; i < N; i++) {
6753: cell_stats_t *A = (cell_stats_t *) a;
6754: cell_stats_t *B = (cell_stats_t *) b;
6756: B->min = PetscMin(A->min,B->min);
6757: B->max = PetscMax(A->max,B->max);
6758: B->sum += A->sum;
6759: B->squaresum += A->squaresum;
6760: B->count += A->count;
6761: }
6762: }
6764: /*@
6765: DMPlexCheckCellShape - Checks the Jacobian of the mapping and computes some minimal statistics.
6767: Input Parameters:
6768: + dm - The DMPlex object
6769: - output - If true, statistics will be displayed on stdout
6771: Note: This is mainly intended for debugging/testing purposes.
6773: Level: developer
6775: .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6776: @*/
6777: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output)
6778: {
6779: PetscMPIInt rank,size;
6780: PetscInt dim, c, cStart, cEnd, cMax, count = 0;
6781: cell_stats_t stats, globalStats;
6782: PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
6783: MPI_Comm comm = PetscObjectComm((PetscObject)dm);
6784: DM dmCoarse;
6789: stats.min = PETSC_MAX_REAL;
6790: stats.max = PETSC_MIN_REAL;
6791: stats.sum = stats.squaresum = 0.;
6792: stats.count = 0;
6794: DMGetCoordinateDim(dm,&dim);
6795: PetscMalloc2(dim * dim, &J, dim * dim, &invJ);
6796: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
6797: DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
6798: cMax = cMax < 0 ? cEnd : cMax;
6799: for (c = cStart; c < cMax; c++) {
6800: PetscInt i;
6801: PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
6803: DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
6804: if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
6805: for (i = 0; i < dim * dim; i++) {
6806: frobJ += J[i] * J[i];
6807: frobInvJ += invJ[i] * invJ[i];
6808: }
6809: cond2 = frobJ * frobInvJ;
6810: cond = PetscSqrtReal(cond2);
6812: stats.min = PetscMin(stats.min,cond);
6813: stats.max = PetscMax(stats.max,cond);
6814: stats.sum += cond;
6815: stats.squaresum += cond2;
6816: stats.count++;
6817: }
6819: MPI_Comm_size(comm,&size);
6820: if (size > 1) {
6821: PetscMPIInt blockLengths[2] = {4,1};
6822: MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
6823: MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType;
6824: MPI_Op statReduce;
6826: MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
6827: MPI_Type_commit(&statType);
6828: MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
6829: MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
6830: MPI_Op_free(&statReduce);
6831: MPI_Type_free(&statType);
6832: } else {
6833: PetscMemcpy(&globalStats,&stats,sizeof(stats));
6834: }
6836: MPI_Comm_rank(comm,&rank);
6837: if (!rank) {
6838: count = globalStats.count;
6839: min = globalStats.min;
6840: max = globalStats.max;
6841: mean = globalStats.sum / globalStats.count;
6842: stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
6843: }
6845: if (output) {
6846: 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);
6847: }
6848: PetscFree2(J,invJ);
6850: DMGetCoarseDM(dm,&dmCoarse);
6851: if (dmCoarse) {
6852: PetscBool isplex;
6854: PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
6855: if (isplex) {
6856: DMPlexCheckCellShape(dmCoarse,output);
6857: }
6858: }
6859: return(0);
6860: }
6862: /* Pointwise interpolation
6863: Just code FEM for now
6864: u^f = I u^c
6865: sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6866: u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6867: I_{ij} = psi^f_i phi^c_j
6868: */
6869: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6870: {
6871: PetscSection gsc, gsf;
6872: PetscInt m, n;
6873: void *ctx;
6874: DM cdm;
6875: PetscBool regular, ismatis;
6879: DMGetGlobalSection(dmFine, &gsf);
6880: PetscSectionGetConstrainedStorageSize(gsf, &m);
6881: DMGetGlobalSection(dmCoarse, &gsc);
6882: PetscSectionGetConstrainedStorageSize(gsc, &n);
6884: PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
6885: MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6886: MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6887: MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
6888: DMGetApplicationContext(dmFine, &ctx);
6890: DMGetCoarseDM(dmFine, &cdm);
6891: DMPlexGetRegularRefinement(dmFine, ®ular);
6892: if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6893: else {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6894: MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6895: if (scaling) {
6896: /* Use naive scaling */
6897: DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6898: }
6899: return(0);
6900: }
6902: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6903: {
6905: VecScatter ctx;
6908: DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6909: MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6910: VecScatterDestroy(&ctx);
6911: return(0);
6912: }
6914: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6915: {
6916: PetscSection gsc, gsf;
6917: PetscInt m, n;
6918: void *ctx;
6919: DM cdm;
6920: PetscBool regular;
6924: DMGetGlobalSection(dmFine, &gsf);
6925: PetscSectionGetConstrainedStorageSize(gsf, &m);
6926: DMGetGlobalSection(dmCoarse, &gsc);
6927: PetscSectionGetConstrainedStorageSize(gsc, &n);
6929: MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6930: MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6931: MatSetType(*mass, dmCoarse->mattype);
6932: DMGetApplicationContext(dmFine, &ctx);
6934: DMGetCoarseDM(dmFine, &cdm);
6935: DMPlexGetRegularRefinement(dmFine, ®ular);
6936: if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6937: else {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6938: MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6939: return(0);
6940: }
6942: /*@
6943: DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6945: Input Parameter:
6946: . dm - The DMPlex object
6948: Output Parameter:
6949: . regular - The flag
6951: Level: intermediate
6953: .seealso: DMPlexSetRegularRefinement()
6954: @*/
6955: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6956: {
6960: *regular = ((DM_Plex *) dm->data)->regularRefinement;
6961: return(0);
6962: }
6964: /*@
6965: DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6967: Input Parameters:
6968: + dm - The DMPlex object
6969: - regular - The flag
6971: Level: intermediate
6973: .seealso: DMPlexGetRegularRefinement()
6974: @*/
6975: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6976: {
6979: ((DM_Plex *) dm->data)->regularRefinement = regular;
6980: return(0);
6981: }
6983: /* anchors */
6984: /*@
6985: DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to
6986: call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
6988: not collective
6990: Input Parameters:
6991: . dm - The DMPlex object
6993: Output Parameters:
6994: + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
6995: - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
6998: Level: intermediate
7000: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7001: @*/
7002: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7003: {
7004: DM_Plex *plex = (DM_Plex *)dm->data;
7009: if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7010: if (anchorSection) *anchorSection = plex->anchorSection;
7011: if (anchorIS) *anchorIS = plex->anchorIS;
7012: return(0);
7013: }
7015: /*@
7016: DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions,
7017: when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
7018: point's degrees of freedom to be a linear combination of other points' degrees of freedom.
7020: After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
7021: DMGetConstraints() and filling in the entries in the constraint matrix.
7023: collective on dm
7025: Input Parameters:
7026: + dm - The DMPlex object
7027: . 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).
7028: - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative).
7030: The reference counts of anchorSection and anchorIS are incremented.
7032: Level: intermediate
7034: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7035: @*/
7036: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7037: {
7038: DM_Plex *plex = (DM_Plex *)dm->data;
7039: PetscMPIInt result;
7044: if (anchorSection) {
7046: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7047: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7048: }
7049: if (anchorIS) {
7051: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7052: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7053: }
7055: PetscObjectReference((PetscObject)anchorSection);
7056: PetscSectionDestroy(&plex->anchorSection);
7057: plex->anchorSection = anchorSection;
7059: PetscObjectReference((PetscObject)anchorIS);
7060: ISDestroy(&plex->anchorIS);
7061: plex->anchorIS = anchorIS;
7063: #if defined(PETSC_USE_DEBUG)
7064: if (anchorIS && anchorSection) {
7065: PetscInt size, a, pStart, pEnd;
7066: const PetscInt *anchors;
7068: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7069: ISGetLocalSize(anchorIS,&size);
7070: ISGetIndices(anchorIS,&anchors);
7071: for (a = 0; a < size; a++) {
7072: PetscInt p;
7074: p = anchors[a];
7075: if (p >= pStart && p < pEnd) {
7076: PetscInt dof;
7078: PetscSectionGetDof(anchorSection,p,&dof);
7079: if (dof) {
7080: PetscErrorCode ierr2;
7082: ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7083: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7084: }
7085: }
7086: }
7087: ISRestoreIndices(anchorIS,&anchors);
7088: }
7089: #endif
7090: /* reset the generic constraints */
7091: DMSetDefaultConstraints(dm,NULL,NULL);
7092: return(0);
7093: }
7095: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7096: {
7097: PetscSection anchorSection;
7098: PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
7103: DMPlexGetAnchors(dm,&anchorSection,NULL);
7104: PetscSectionCreate(PETSC_COMM_SELF,cSec);
7105: PetscSectionGetNumFields(section,&numFields);
7106: if (numFields) {
7107: PetscInt f;
7108: PetscSectionSetNumFields(*cSec,numFields);
7110: for (f = 0; f < numFields; f++) {
7111: PetscInt numComp;
7113: PetscSectionGetFieldComponents(section,f,&numComp);
7114: PetscSectionSetFieldComponents(*cSec,f,numComp);
7115: }
7116: }
7117: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7118: PetscSectionGetChart(section,&sStart,&sEnd);
7119: pStart = PetscMax(pStart,sStart);
7120: pEnd = PetscMin(pEnd,sEnd);
7121: pEnd = PetscMax(pStart,pEnd);
7122: PetscSectionSetChart(*cSec,pStart,pEnd);
7123: for (p = pStart; p < pEnd; p++) {
7124: PetscSectionGetDof(anchorSection,p,&dof);
7125: if (dof) {
7126: PetscSectionGetDof(section,p,&dof);
7127: PetscSectionSetDof(*cSec,p,dof);
7128: for (f = 0; f < numFields; f++) {
7129: PetscSectionGetFieldDof(section,p,f,&dof);
7130: PetscSectionSetFieldDof(*cSec,p,f,dof);
7131: }
7132: }
7133: }
7134: PetscSectionSetUp(*cSec);
7135: return(0);
7136: }
7138: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7139: {
7140: PetscSection aSec;
7141: PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7142: const PetscInt *anchors;
7143: PetscInt numFields, f;
7144: IS aIS;
7149: PetscSectionGetStorageSize(cSec, &m);
7150: PetscSectionGetStorageSize(section, &n);
7151: MatCreate(PETSC_COMM_SELF,cMat);
7152: MatSetSizes(*cMat,m,n,m,n);
7153: MatSetType(*cMat,MATSEQAIJ);
7154: DMPlexGetAnchors(dm,&aSec,&aIS);
7155: ISGetIndices(aIS,&anchors);
7156: /* cSec will be a subset of aSec and section */
7157: PetscSectionGetChart(cSec,&pStart,&pEnd);
7158: PetscMalloc1(m+1,&i);
7159: i[0] = 0;
7160: PetscSectionGetNumFields(section,&numFields);
7161: for (p = pStart; p < pEnd; p++) {
7162: PetscInt rDof, rOff, r;
7164: PetscSectionGetDof(aSec,p,&rDof);
7165: if (!rDof) continue;
7166: PetscSectionGetOffset(aSec,p,&rOff);
7167: if (numFields) {
7168: for (f = 0; f < numFields; f++) {
7169: annz = 0;
7170: for (r = 0; r < rDof; r++) {
7171: a = anchors[rOff + r];
7172: PetscSectionGetFieldDof(section,a,f,&aDof);
7173: annz += aDof;
7174: }
7175: PetscSectionGetFieldDof(cSec,p,f,&dof);
7176: PetscSectionGetFieldOffset(cSec,p,f,&off);
7177: for (q = 0; q < dof; q++) {
7178: i[off + q + 1] = i[off + q] + annz;
7179: }
7180: }
7181: }
7182: else {
7183: annz = 0;
7184: for (q = 0; q < dof; q++) {
7185: a = anchors[off + q];
7186: PetscSectionGetDof(section,a,&aDof);
7187: annz += aDof;
7188: }
7189: PetscSectionGetDof(cSec,p,&dof);
7190: PetscSectionGetOffset(cSec,p,&off);
7191: for (q = 0; q < dof; q++) {
7192: i[off + q + 1] = i[off + q] + annz;
7193: }
7194: }
7195: }
7196: nnz = i[m];
7197: PetscMalloc1(nnz,&j);
7198: offset = 0;
7199: for (p = pStart; p < pEnd; p++) {
7200: if (numFields) {
7201: for (f = 0; f < numFields; f++) {
7202: PetscSectionGetFieldDof(cSec,p,f,&dof);
7203: for (q = 0; q < dof; q++) {
7204: PetscInt rDof, rOff, r;
7205: PetscSectionGetDof(aSec,p,&rDof);
7206: PetscSectionGetOffset(aSec,p,&rOff);
7207: for (r = 0; r < rDof; r++) {
7208: PetscInt s;
7210: a = anchors[rOff + r];
7211: PetscSectionGetFieldDof(section,a,f,&aDof);
7212: PetscSectionGetFieldOffset(section,a,f,&aOff);
7213: for (s = 0; s < aDof; s++) {
7214: j[offset++] = aOff + s;
7215: }
7216: }
7217: }
7218: }
7219: }
7220: else {
7221: PetscSectionGetDof(cSec,p,&dof);
7222: for (q = 0; q < dof; q++) {
7223: PetscInt rDof, rOff, r;
7224: PetscSectionGetDof(aSec,p,&rDof);
7225: PetscSectionGetOffset(aSec,p,&rOff);
7226: for (r = 0; r < rDof; r++) {
7227: PetscInt s;
7229: a = anchors[rOff + r];
7230: PetscSectionGetDof(section,a,&aDof);
7231: PetscSectionGetOffset(section,a,&aOff);
7232: for (s = 0; s < aDof; s++) {
7233: j[offset++] = aOff + s;
7234: }
7235: }
7236: }
7237: }
7238: }
7239: MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7240: PetscFree(i);
7241: PetscFree(j);
7242: ISRestoreIndices(aIS,&anchors);
7243: return(0);
7244: }
7246: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7247: {
7248: DM_Plex *plex = (DM_Plex *)dm->data;
7249: PetscSection anchorSection, section, cSec;
7250: Mat cMat;
7255: DMPlexGetAnchors(dm,&anchorSection,NULL);
7256: if (anchorSection) {
7257: PetscInt Nf;
7259: DMGetSection(dm,§ion);
7260: DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7261: DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7262: DMGetNumFields(dm,&Nf);
7263: if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7264: DMSetDefaultConstraints(dm,cSec,cMat);
7265: PetscSectionDestroy(&cSec);
7266: MatDestroy(&cMat);
7267: }
7268: return(0);
7269: }
7271: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7272: {
7273: IS subis;
7274: PetscSection section, subsection;
7278: DMGetDefaultSection(dm, §ion);
7279: if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7280: if (!subdm) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7281: /* Create subdomain */
7282: DMPlexFilter(dm, label, value, subdm);
7283: /* Create submodel */
7284: DMPlexCreateSubpointIS(*subdm, &subis);
7285: PetscSectionCreateSubmeshSection(section, subis, &subsection);
7286: ISDestroy(&subis);
7287: DMSetDefaultSection(*subdm, subsection);
7288: PetscSectionDestroy(&subsection);
7289: DMCopyDisc(dm, *subdm);
7290: /* Create map from submodel to global model */
7291: if (is) {
7292: PetscSection sectionGlobal, subsectionGlobal;
7293: IS spIS;
7294: const PetscInt *spmap;
7295: PetscInt *subIndices;
7296: PetscInt subSize = 0, subOff = 0, pStart, pEnd, p;
7297: PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
7299: DMPlexCreateSubpointIS(*subdm, &spIS);
7300: ISGetIndices(spIS, &spmap);
7301: PetscSectionGetNumFields(section, &Nf);
7302: DMGetDefaultGlobalSection(dm, §ionGlobal);
7303: DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);
7304: PetscSectionGetChart(subsection, &pStart, &pEnd);
7305: for (p = pStart; p < pEnd; ++p) {
7306: PetscInt gdof, pSubSize = 0;
7308: PetscSectionGetDof(sectionGlobal, p, &gdof);
7309: if (gdof > 0) {
7310: for (f = 0; f < Nf; ++f) {
7311: PetscInt fdof, fcdof;
7313: PetscSectionGetFieldDof(subsection, p, f, &fdof);
7314: PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7315: pSubSize += fdof-fcdof;
7316: }
7317: subSize += pSubSize;
7318: if (pSubSize) {
7319: if (bs < 0) {
7320: bs = pSubSize;
7321: } else if (bs != pSubSize) {
7322: /* Layout does not admit a pointwise block size */
7323: bs = 1;
7324: }
7325: }
7326: }
7327: }
7328: /* Must have same blocksize on all procs (some might have no points) */
7329: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7330: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7331: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7332: else {bs = bsMinMax[0];}
7333: PetscMalloc1(subSize, &subIndices);
7334: for (p = pStart; p < pEnd; ++p) {
7335: PetscInt gdof, goff;
7337: PetscSectionGetDof(subsectionGlobal, p, &gdof);
7338: if (gdof > 0) {
7339: const PetscInt point = spmap[p];
7341: PetscSectionGetOffset(sectionGlobal, point, &goff);
7342: for (f = 0; f < Nf; ++f) {
7343: PetscInt fdof, fcdof, fc, f2, poff = 0;
7345: /* Can get rid of this loop by storing field information in the global section */
7346: for (f2 = 0; f2 < f; ++f2) {
7347: PetscSectionGetFieldDof(section, p, f2, &fdof);
7348: PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7349: poff += fdof-fcdof;
7350: }
7351: PetscSectionGetFieldDof(section, p, f, &fdof);
7352: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7353: for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7354: subIndices[subOff] = goff+poff+fc;
7355: }
7356: }
7357: }
7358: }
7359: ISRestoreIndices(spIS, &spmap);
7360: ISDestroy(&spIS);
7361: ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7362: if (bs > 1) {
7363: /* We need to check that the block size does not come from non-contiguous fields */
7364: PetscInt i, j, set = 1;
7365: for (i = 0; i < subSize; i += bs) {
7366: for (j = 0; j < bs; ++j) {
7367: if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7368: }
7369: }
7370: if (set) {ISSetBlockSize(*is, bs);}
7371: }
7372: /* Attach nullspace */
7373: for (f = 0; f < Nf; ++f) {
7374: (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7375: if ((*subdm)->nullspaceConstructors[f]) break;
7376: }
7377: if (f < Nf) {
7378: MatNullSpace nullSpace;
7380: (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7381: PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7382: MatNullSpaceDestroy(&nullSpace);
7383: }
7384: }
7385: return(0);
7386: }