Actual source code: plex.c
petsc-3.9.4 2018-09-11
1: #include <petsc/private/dmpleximpl.h>
2: #include <petsc/private/isimpl.h>
3: #include <petsc/private/vecimpl.h>
4: #include <petsc/private/glvisvecimpl.h>
5: #include <petscsf.h>
6: #include <petscds.h>
7: #include <petscdraw.h>
9: /* Logging support */
10: PetscLogEvent DMPLEX_Interpolate, PETSCPARTITIONER_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;
12: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
14: /*@
15: DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells.
16: 3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D.
18: Collective
20: Input Parameters:
21: . dm - The DMPlex object
23: Output Parameters:
24: . dmRefined - The refined DMPlex object
26: Note: Returns NULL if the mesh is already a tensor product mesh.
28: Level: intermediate
30: .seealso: DMPlexCreate(), DMPlexSetRefinementUniform()
31: @*/
32: PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined)
33: {
34: PetscInt dim, cMax, fMax, cStart, cEnd, coneSize;
35: CellRefiner cellRefiner;
36: PetscBool lop, allnoop, localized;
37: PetscErrorCode ierr;
41: DMGetDimension(dm, &dim);
42: DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
43: if (cMax >= 0 || fMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle hybrid meshes yet");
44: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
45: if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
46: else {
47: DMPlexGetConeSize(dm,cStart,&coneSize);
48: switch (dim) {
49: case 1:
50: cellRefiner = REFINER_NOOP;
51: break;
52: case 2:
53: switch (coneSize) {
54: case 3:
55: cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
56: break;
57: case 4:
58: cellRefiner = REFINER_NOOP;
59: break;
60: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
61: }
62: break;
63: case 3:
64: switch (coneSize) {
65: case 4:
66: cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
67: break;
68: case 6:
69: cellRefiner = REFINER_NOOP;
70: break;
71: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
72: }
73: break;
74: default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
75: }
76: }
77: /* return if we don't need to refine */
78: lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
79: MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
80: if (allnoop) {
81: *dmRefined = NULL;
82: return(0);
83: }
84: DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
85: DMCopyBoundary(dm, *dmRefined);
86: DMGetCoordinatesLocalized(dm, &localized);
87: if (localized) {
88: DMLocalizeCoordinates(*dmRefined);
89: }
90: return(0);
91: }
93: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
94: {
95: PetscInt dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior;
96: PetscInt vcdof[2] = {0,0}, globalvcdof[2];
100: *ft = PETSC_VTK_POINT_FIELD;
101: DMGetDimension(dm, &dim);
102: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
103: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
104: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
105: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
106: PetscSectionGetChart(section, &pStart, &pEnd);
107: if (field >= 0) {
108: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);}
109: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);}
110: } else {
111: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vcdof[0]);}
112: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &vcdof[1]);}
113: }
114: MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
115: if (globalvcdof[0]) {
116: *sStart = vStart;
117: *sEnd = vEnd;
118: if (globalvcdof[0] == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
119: else *ft = PETSC_VTK_POINT_FIELD;
120: } else if (globalvcdof[1]) {
121: *sStart = cStart;
122: *sEnd = cEnd;
123: if (globalvcdof[1] == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
124: else *ft = PETSC_VTK_CELL_FIELD;
125: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
126: return(0);
127: }
129: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
130: {
131: DM dm;
132: PetscSection s;
133: PetscDraw draw, popup;
134: DM cdm;
135: PetscSection coordSection;
136: Vec coordinates;
137: const PetscScalar *coords, *array;
138: PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
139: PetscReal vbound[2], time;
140: PetscBool isnull, flg;
141: PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
142: const char *name;
143: char title[PETSC_MAX_PATH_LEN];
144: PetscErrorCode ierr;
147: PetscViewerDrawGetDraw(viewer, 0, &draw);
148: PetscDrawIsNull(draw, &isnull);
149: if (isnull) return(0);
151: VecGetDM(v, &dm);
152: DMGetCoordinateDim(dm, &dim);
153: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
154: DMGetDefaultSection(dm, &s);
155: PetscSectionGetNumFields(s, &Nf);
156: DMGetCoarsenLevel(dm, &level);
157: DMGetCoordinateDM(dm, &cdm);
158: DMGetDefaultSection(cdm, &coordSection);
159: DMGetCoordinatesLocal(dm, &coordinates);
160: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
161: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
163: PetscObjectGetName((PetscObject) v, &name);
164: DMGetOutputSequenceNumber(dm, &step, &time);
166: VecGetLocalSize(coordinates, &N);
167: VecGetArrayRead(coordinates, &coords);
168: for (c = 0; c < N; c += dim) {
169: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
170: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
171: }
172: VecRestoreArrayRead(coordinates, &coords);
173: PetscDrawClear(draw);
175: /* Could implement something like DMDASelectFields() */
176: for (f = 0; f < Nf; ++f) {
177: DM fdm = dm;
178: Vec fv = v;
179: IS fis;
180: char prefix[PETSC_MAX_PATH_LEN];
181: const char *fname;
183: PetscSectionGetFieldComponents(s, f, &Nc);
184: PetscSectionGetFieldName(s, f, &fname);
186: if (v->hdr.prefix) {PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));}
187: else {prefix[0] = '\0';}
188: if (Nf > 1) {
189: DMCreateSubDM(dm, 1, &f, &fis, &fdm);
190: VecGetSubVector(v, fis, &fv);
191: PetscStrlcat(prefix, fname,sizeof(prefix));
192: PetscStrlcat(prefix, "_",sizeof(prefix));
193: }
194: for (comp = 0; comp < Nc; ++comp, ++w) {
195: PetscInt nmax = 2;
197: PetscViewerDrawGetDraw(viewer, w, &draw);
198: if (Nc > 1) {PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);}
199: else {PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);}
200: PetscDrawSetTitle(draw, title);
202: /* TODO Get max and min only for this component */
203: PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
204: if (!flg) {
205: VecMin(fv, NULL, &vbound[0]);
206: VecMax(fv, NULL, &vbound[1]);
207: if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
208: }
209: PetscDrawGetPopup(draw, &popup);
210: PetscDrawScalePopup(popup, vbound[0], vbound[1]);
211: PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
213: VecGetArrayRead(fv, &array);
214: for (c = cStart; c < cEnd; ++c) {
215: PetscScalar *coords = NULL, *a = NULL;
216: PetscInt numCoords, color[4] = {-1,-1,-1,-1};
218: DMPlexPointLocalRead(fdm, c, array, &a);
219: if (a) {
220: color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
221: color[1] = color[2] = color[3] = color[0];
222: } else {
223: PetscScalar *vals = NULL;
224: PetscInt numVals, va;
226: DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
227: 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);
228: switch (numVals/Nc) {
229: case 3: /* P1 Triangle */
230: case 4: /* P1 Quadrangle */
231: for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
232: break;
233: case 6: /* P2 Triangle */
234: case 8: /* P2 Quadrangle */
235: for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
236: break;
237: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
238: }
239: DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
240: }
241: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
242: switch (numCoords) {
243: case 6:
244: 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]);
245: break;
246: case 8:
247: 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]);
248: 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]);
249: break;
250: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
251: }
252: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
253: }
254: VecRestoreArrayRead(fv, &array);
255: PetscDrawFlush(draw);
256: PetscDrawPause(draw);
257: PetscDrawSave(draw);
258: }
259: if (Nf > 1) {
260: VecRestoreSubVector(v, fis, &fv);
261: ISDestroy(&fis);
262: DMDestroy(&fdm);
263: }
264: }
265: return(0);
266: }
268: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
269: {
270: DM dm;
271: Vec locv;
272: const char *name;
273: PetscSection section;
274: PetscInt pStart, pEnd;
275: PetscViewerVTKFieldType ft;
276: PetscErrorCode ierr;
279: VecGetDM(v, &dm);
280: DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
281: PetscObjectGetName((PetscObject) v, &name);
282: PetscObjectSetName((PetscObject) locv, name);
283: VecCopy(v, locv);
284: DMGetDefaultSection(dm, §ion);
285: DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
286: PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) locv);
287: return(0);
288: }
290: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
291: {
292: DM dm;
293: PetscBool isvtk, ishdf5, isdraw, isglvis;
297: VecGetDM(v, &dm);
298: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
299: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
300: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
301: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
302: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
303: if (isvtk || ishdf5 || isdraw || isglvis) {
304: PetscInt i,numFields;
305: PetscObject fe;
306: PetscBool fem = PETSC_FALSE;
307: Vec locv = v;
308: const char *name;
309: PetscInt step;
310: PetscReal time;
312: DMGetNumFields(dm, &numFields);
313: for (i=0; i<numFields; i++) {
314: DMGetField(dm, i, &fe);
315: if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
316: }
317: if (fem) {
318: DMGetLocalVector(dm, &locv);
319: PetscObjectGetName((PetscObject) v, &name);
320: PetscObjectSetName((PetscObject) locv, name);
321: VecCopy(v, locv);
322: DMGetOutputSequenceNumber(dm, NULL, &time);
323: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
324: }
325: if (isvtk) {
326: VecView_Plex_Local_VTK(locv, viewer);
327: } else if (ishdf5) {
328: #if defined(PETSC_HAVE_HDF5)
329: VecView_Plex_Local_HDF5_Internal(locv, viewer);
330: #else
331: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
332: #endif
333: } else if (isdraw) {
334: VecView_Plex_Local_Draw(locv, viewer);
335: } else if (isglvis) {
336: DMGetOutputSequenceNumber(dm, &step, NULL);
337: PetscViewerGLVisSetSnapId(viewer, step);
338: VecView_GLVis(locv, viewer);
339: }
340: if (fem) {DMRestoreLocalVector(dm, &locv);}
341: } else {
342: PetscBool isseq;
344: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
345: if (isseq) {VecView_Seq(v, viewer);}
346: else {VecView_MPI(v, viewer);}
347: }
348: return(0);
349: }
351: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
352: {
353: DM dm;
354: PetscBool isvtk, ishdf5, isdraw, isglvis;
358: VecGetDM(v, &dm);
359: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
360: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
361: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
362: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
363: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
364: if (isvtk || isdraw || isglvis) {
365: Vec locv;
366: const char *name;
368: DMGetLocalVector(dm, &locv);
369: PetscObjectGetName((PetscObject) v, &name);
370: PetscObjectSetName((PetscObject) locv, name);
371: DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
372: DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
373: VecView_Plex_Local(locv, viewer);
374: DMRestoreLocalVector(dm, &locv);
375: } else if (ishdf5) {
376: #if defined(PETSC_HAVE_HDF5)
377: VecView_Plex_HDF5_Internal(v, viewer);
378: #else
379: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
380: #endif
381: } else {
382: PetscBool isseq;
384: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
385: if (isseq) {VecView_Seq(v, viewer);}
386: else {VecView_MPI(v, viewer);}
387: }
388: return(0);
389: }
391: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
392: {
393: DM dm;
394: MPI_Comm comm;
395: PetscViewerFormat format;
396: Vec v;
397: PetscBool isvtk, ishdf5;
398: PetscErrorCode ierr;
401: VecGetDM(originalv, &dm);
402: PetscObjectGetComm((PetscObject) originalv, &comm);
403: if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
404: PetscViewerGetFormat(viewer, &format);
405: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
406: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
407: if (format == PETSC_VIEWER_NATIVE) {
408: const char *vecname;
409: PetscInt n, nroots;
411: if (dm->sfNatural) {
412: VecGetLocalSize(originalv, &n);
413: PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
414: if (n == nroots) {
415: DMGetGlobalVector(dm, &v);
416: DMPlexGlobalToNaturalBegin(dm, originalv, v);
417: DMPlexGlobalToNaturalEnd(dm, originalv, v);
418: PetscObjectGetName((PetscObject) originalv, &vecname);
419: PetscObjectSetName((PetscObject) v, vecname);
420: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
421: } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
422: } else {
423: /* we are viewing a natural DMPlex vec. */
424: v = originalv;
425: }
426: if (ishdf5) {
427: #if defined(PETSC_HAVE_HDF5)
428: VecView_Plex_HDF5_Native_Internal(v, viewer);
429: #else
430: SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
431: #endif
432: } else if (isvtk) {
433: SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
434: } else {
435: PetscBool isseq;
437: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
438: if (isseq) {VecView_Seq(v, viewer);}
439: else {VecView_MPI(v, viewer);}
440: }
441: if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
442: return(0);
443: }
445: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
446: {
447: DM dm;
448: PetscBool ishdf5;
452: VecGetDM(v, &dm);
453: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
454: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
455: if (ishdf5) {
456: DM dmBC;
457: Vec gv;
458: const char *name;
460: DMGetOutputDM(dm, &dmBC);
461: DMGetGlobalVector(dmBC, &gv);
462: PetscObjectGetName((PetscObject) v, &name);
463: PetscObjectSetName((PetscObject) gv, name);
464: VecLoad_Default(gv, viewer);
465: DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
466: DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
467: DMRestoreGlobalVector(dmBC, &gv);
468: } else {
469: VecLoad_Default(v, viewer);
470: }
471: return(0);
472: }
474: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
475: {
476: DM dm;
477: PetscBool ishdf5;
481: VecGetDM(v, &dm);
482: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
483: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
484: if (ishdf5) {
485: #if defined(PETSC_HAVE_HDF5)
486: VecLoad_Plex_HDF5_Internal(v, viewer);
487: #else
488: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
489: #endif
490: } else {
491: VecLoad_Default(v, viewer);
492: }
493: return(0);
494: }
496: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
497: {
498: DM dm;
499: PetscViewerFormat format;
500: PetscBool ishdf5;
501: PetscErrorCode ierr;
504: VecGetDM(originalv, &dm);
505: if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
506: PetscViewerGetFormat(viewer, &format);
507: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
508: if (format == PETSC_VIEWER_NATIVE) {
509: if (dm->sfNatural) {
510: if (ishdf5) {
511: #if defined(PETSC_HAVE_HDF5)
512: Vec v;
513: const char *vecname;
515: DMGetGlobalVector(dm, &v);
516: PetscObjectGetName((PetscObject) originalv, &vecname);
517: PetscObjectSetName((PetscObject) v, vecname);
518: VecLoad_Plex_HDF5_Native_Internal(v, viewer);
519: DMPlexNaturalToGlobalBegin(dm, v, originalv);
520: DMPlexNaturalToGlobalEnd(dm, v, originalv);
521: DMRestoreGlobalVector(dm, &v);
522: #else
523: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
524: #endif
525: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
526: }
527: }
528: return(0);
529: }
531: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
532: {
533: PetscSection coordSection;
534: Vec coordinates;
535: DMLabel depthLabel;
536: const char *name[4];
537: const PetscScalar *a;
538: PetscInt dim, pStart, pEnd, cStart, cEnd, c;
539: PetscErrorCode ierr;
542: DMGetDimension(dm, &dim);
543: DMGetCoordinatesLocal(dm, &coordinates);
544: DMGetCoordinateSection(dm, &coordSection);
545: DMPlexGetDepthLabel(dm, &depthLabel);
546: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
547: PetscSectionGetChart(coordSection, &pStart, &pEnd);
548: VecGetArrayRead(coordinates, &a);
549: name[0] = "vertex";
550: name[1] = "edge";
551: name[dim-1] = "face";
552: name[dim] = "cell";
553: for (c = cStart; c < cEnd; ++c) {
554: PetscInt *closure = NULL;
555: PetscInt closureSize, cl;
557: PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);
558: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
559: PetscViewerASCIIPushTab(viewer);
560: for (cl = 0; cl < closureSize*2; cl += 2) {
561: PetscInt point = closure[cl], depth, dof, off, d, p;
563: if ((point < pStart) || (point >= pEnd)) continue;
564: PetscSectionGetDof(coordSection, point, &dof);
565: if (!dof) continue;
566: DMLabelGetValue(depthLabel, point, &depth);
567: PetscSectionGetOffset(coordSection, point, &off);
568: PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
569: for (p = 0; p < dof/dim; ++p) {
570: PetscViewerASCIIPrintf(viewer, " (");
571: for (d = 0; d < dim; ++d) {
572: if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
573: PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
574: }
575: PetscViewerASCIIPrintf(viewer, ")");
576: }
577: PetscViewerASCIIPrintf(viewer, "\n");
578: }
579: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
580: PetscViewerASCIIPopTab(viewer);
581: }
582: VecRestoreArrayRead(coordinates, &a);
583: return(0);
584: }
586: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
587: {
588: DM_Plex *mesh = (DM_Plex*) dm->data;
589: DM cdm;
590: DMLabel markers;
591: PetscSection coordSection;
592: Vec coordinates;
593: PetscViewerFormat format;
594: PetscErrorCode ierr;
597: DMGetCoordinateDM(dm, &cdm);
598: DMGetDefaultSection(cdm, &coordSection);
599: DMGetCoordinatesLocal(dm, &coordinates);
600: PetscViewerGetFormat(viewer, &format);
601: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
602: const char *name;
603: PetscInt dim, cellHeight, maxConeSize, maxSupportSize;
604: PetscInt pStart, pEnd, p;
605: PetscMPIInt rank, size;
607: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
608: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
609: PetscObjectGetName((PetscObject) dm, &name);
610: DMPlexGetChart(dm, &pStart, &pEnd);
611: DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
612: DMGetDimension(dm, &dim);
613: DMPlexGetVTKCellHeight(dm, &cellHeight);
614: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
615: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
616: if (cellHeight) {PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);}
617: PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
618: PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
619: PetscViewerASCIIPushSynchronized(viewer);
620: PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);
621: for (p = pStart; p < pEnd; ++p) {
622: PetscInt dof, off, s;
624: PetscSectionGetDof(mesh->supportSection, p, &dof);
625: PetscSectionGetOffset(mesh->supportSection, p, &off);
626: for (s = off; s < off+dof; ++s) {
627: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
628: }
629: }
630: PetscViewerFlush(viewer);
631: PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
632: for (p = pStart; p < pEnd; ++p) {
633: PetscInt dof, off, c;
635: PetscSectionGetDof(mesh->coneSection, p, &dof);
636: PetscSectionGetOffset(mesh->coneSection, p, &off);
637: for (c = off; c < off+dof; ++c) {
638: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
639: }
640: }
641: PetscViewerFlush(viewer);
642: PetscViewerASCIIPopSynchronized(viewer);
643: PetscSectionGetChart(coordSection, &pStart, NULL);
644: if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
645: DMGetLabel(dm, "marker", &markers);
646: DMLabelView(markers,viewer);
647: if (size > 1) {
648: PetscSF sf;
650: DMGetPointSF(dm, &sf);
651: PetscSFView(sf, viewer);
652: }
653: PetscViewerFlush(viewer);
654: } else if (format == PETSC_VIEWER_ASCII_LATEX) {
655: const char *name, *color;
656: const char *defcolors[3] = {"gray", "orange", "green"};
657: const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
658: PetscReal scale = 2.0;
659: PetscBool useNumbers = PETSC_TRUE, useLabels, useColors;
660: double tcoords[3];
661: PetscScalar *coords;
662: PetscInt numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
663: PetscMPIInt rank, size;
664: char **names, **colors, **lcolors;
666: DMGetDimension(dm, &dim);
667: DMPlexGetDepth(dm, &depth);
668: DMGetNumLabels(dm, &numLabels);
669: numLabels = PetscMax(numLabels, 10);
670: numColors = 10;
671: numLColors = 10;
672: PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
673: PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
674: PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
675: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
676: if (!useLabels) numLabels = 0;
677: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
678: if (!useColors) {
679: numColors = 3;
680: for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
681: }
682: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
683: if (!useColors) {
684: numLColors = 4;
685: for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
686: }
687: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
688: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
689: PetscObjectGetName((PetscObject) dm, &name);
690: PetscViewerASCIIPrintf(viewer, "\
691: \\documentclass[tikz]{standalone}\n\n\
692: \\usepackage{pgflibraryshapes}\n\
693: \\usetikzlibrary{backgrounds}\n\
694: \\usetikzlibrary{arrows}\n\
695: \\begin{document}\n");
696: if (size > 1) {
697: PetscViewerASCIIPrintf(viewer, "%s for process ", name);
698: for (p = 0; p < size; ++p) {
699: if (p > 0 && p == size-1) {
700: PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
701: } else if (p > 0) {
702: PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
703: }
704: PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
705: }
706: PetscViewerASCIIPrintf(viewer, ".\n\n\n");
707: }
708: PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);
709: /* Plot vertices */
710: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
711: VecGetArray(coordinates, &coords);
712: PetscViewerASCIIPushSynchronized(viewer);
713: for (v = vStart; v < vEnd; ++v) {
714: PetscInt off, dof, d;
715: PetscBool isLabeled = PETSC_FALSE;
717: PetscSectionGetDof(coordSection, v, &dof);
718: PetscSectionGetOffset(coordSection, v, &off);
719: PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
720: if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
721: for (d = 0; d < dof; ++d) {
722: tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
723: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
724: }
725: /* Rotate coordinates since PGF makes z point out of the page instead of up */
726: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
727: for (d = 0; d < dof; ++d) {
728: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
729: PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
730: }
731: color = colors[rank%numColors];
732: for (l = 0; l < numLabels; ++l) {
733: PetscInt val;
734: DMGetLabelValue(dm, names[l], v, &val);
735: if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
736: }
737: if (useNumbers) {
738: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
739: } else {
740: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
741: }
742: }
743: VecRestoreArray(coordinates, &coords);
744: PetscViewerFlush(viewer);
745: /* Plot edges */
746: if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
747: if (dim < 3 && useNumbers) {
748: VecGetArray(coordinates, &coords);
749: PetscViewerASCIIPrintf(viewer, "\\path\n");
750: for (e = eStart; e < eEnd; ++e) {
751: const PetscInt *cone;
752: PetscInt coneSize, offA, offB, dof, d;
754: DMPlexGetConeSize(dm, e, &coneSize);
755: if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
756: DMPlexGetCone(dm, e, &cone);
757: PetscSectionGetDof(coordSection, cone[0], &dof);
758: PetscSectionGetOffset(coordSection, cone[0], &offA);
759: PetscSectionGetOffset(coordSection, cone[1], &offB);
760: PetscViewerASCIISynchronizedPrintf(viewer, "(");
761: for (d = 0; d < dof; ++d) {
762: tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
763: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
764: }
765: /* Rotate coordinates since PGF makes z point out of the page instead of up */
766: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
767: for (d = 0; d < dof; ++d) {
768: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
769: PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
770: }
771: color = colors[rank%numColors];
772: for (l = 0; l < numLabels; ++l) {
773: PetscInt val;
774: DMGetLabelValue(dm, names[l], v, &val);
775: if (val >= 0) {color = lcolors[l%numLColors]; break;}
776: }
777: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
778: }
779: VecRestoreArray(coordinates, &coords);
780: PetscViewerFlush(viewer);
781: PetscViewerASCIIPrintf(viewer, "(0,0);\n");
782: }
783: /* Plot cells */
784: if (dim == 3 || !useNumbers) {
785: for (e = eStart; e < eEnd; ++e) {
786: const PetscInt *cone;
788: color = colors[rank%numColors];
789: for (l = 0; l < numLabels; ++l) {
790: PetscInt val;
791: DMGetLabelValue(dm, names[l], e, &val);
792: if (val >= 0) {color = lcolors[l%numLColors]; break;}
793: }
794: DMPlexGetCone(dm, e, &cone);
795: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
796: }
797: } else {
798: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
799: for (c = cStart; c < cEnd; ++c) {
800: PetscInt *closure = NULL;
801: PetscInt closureSize, firstPoint = -1;
803: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
804: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
805: for (p = 0; p < closureSize*2; p += 2) {
806: const PetscInt point = closure[p];
808: if ((point < vStart) || (point >= vEnd)) continue;
809: if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
810: PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
811: if (firstPoint < 0) firstPoint = point;
812: }
813: /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
814: PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
815: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
816: }
817: }
818: PetscViewerFlush(viewer);
819: PetscViewerASCIIPopSynchronized(viewer);
820: PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
821: PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
822: for (l = 0; l < numLabels; ++l) {PetscFree(names[l]);}
823: for (c = 0; c < numColors; ++c) {PetscFree(colors[c]);}
824: for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
825: PetscFree3(names, colors, lcolors);
826: } else {
827: MPI_Comm comm;
828: PetscInt *sizes, *hybsizes;
829: PetscInt locDepth, depth, cellHeight, dim, d, pMax[4];
830: PetscInt pStart, pEnd, p;
831: PetscInt numLabels, l;
832: const char *name;
833: PetscMPIInt size;
835: PetscObjectGetComm((PetscObject)dm,&comm);
836: MPI_Comm_size(comm, &size);
837: DMGetDimension(dm, &dim);
838: DMPlexGetVTKCellHeight(dm, &cellHeight);
839: PetscObjectGetName((PetscObject) dm, &name);
840: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
841: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
842: if (cellHeight) {PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);}
843: DMPlexGetDepth(dm, &locDepth);
844: MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
845: DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
846: PetscMalloc2(size,&sizes,size,&hybsizes);
847: if (depth == 1) {
848: DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
849: pEnd = pEnd - pStart;
850: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
851: PetscViewerASCIIPrintf(viewer, " %d-cells:", 0);
852: for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
853: PetscViewerASCIIPrintf(viewer, "\n");
854: DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
855: pEnd = pEnd - pStart;
856: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
857: PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);
858: for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
859: PetscViewerASCIIPrintf(viewer, "\n");
860: } else {
861: PetscMPIInt rank;
862: MPI_Comm_rank(comm, &rank);
863: for (d = 0; d <= dim; d++) {
864: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
865: pEnd -= pStart;
866: pMax[d] -= pStart;
867: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
868: MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
869: PetscViewerASCIIPrintf(viewer, " %D-cells:", d);
870: for (p = 0; p < size; ++p) {
871: if (!rank) {
872: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
873: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
874: }
875: }
876: PetscViewerASCIIPrintf(viewer, "\n");
877: }
878: }
879: PetscFree2(sizes,hybsizes);
880: DMGetNumLabels(dm, &numLabels);
881: if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
882: for (l = 0; l < numLabels; ++l) {
883: DMLabel label;
884: const char *name;
885: IS valueIS;
886: const PetscInt *values;
887: PetscInt numValues, v;
889: DMGetLabelName(dm, l, &name);
890: DMGetLabel(dm, name, &label);
891: DMLabelGetNumValues(label, &numValues);
892: PetscViewerASCIIPrintf(viewer, " %s: %D strata with value/size (", name, numValues);
893: DMLabelGetValueIS(label, &valueIS);
894: ISGetIndices(valueIS, &values);
895: PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
896: for (v = 0; v < numValues; ++v) {
897: PetscInt size;
899: DMLabelGetStratumSize(label, values[v], &size);
900: if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
901: PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
902: }
903: PetscViewerASCIIPrintf(viewer, ")\n");
904: PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
905: ISRestoreIndices(valueIS, &values);
906: ISDestroy(&valueIS);
907: }
908: DMGetCoarseDM(dm, &cdm);
909: if (cdm) {
910: PetscViewerASCIIPushTab(viewer);
911: DMPlexView_Ascii(cdm, viewer);
912: PetscViewerASCIIPopTab(viewer);
913: }
914: }
915: return(0);
916: }
918: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
919: {
920: PetscDraw draw;
921: DM cdm;
922: PetscSection coordSection;
923: Vec coordinates;
924: const PetscScalar *coords;
925: PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
926: PetscBool isnull;
927: PetscInt dim, vStart, vEnd, cStart, cEnd, c, N;
928: PetscErrorCode ierr;
931: DMGetCoordinateDim(dm, &dim);
932: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
933: DMGetCoordinateDM(dm, &cdm);
934: DMGetDefaultSection(cdm, &coordSection);
935: DMGetCoordinatesLocal(dm, &coordinates);
936: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
937: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
939: PetscViewerDrawGetDraw(viewer, 0, &draw);
940: PetscDrawIsNull(draw, &isnull);
941: if (isnull) return(0);
942: PetscDrawSetTitle(draw, "Mesh");
944: VecGetLocalSize(coordinates, &N);
945: VecGetArrayRead(coordinates, &coords);
946: for (c = 0; c < N; c += dim) {
947: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
948: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
949: }
950: VecRestoreArrayRead(coordinates, &coords);
951: MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
952: MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
953: PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
954: PetscDrawClear(draw);
956: for (c = cStart; c < cEnd; ++c) {
957: PetscScalar *coords = NULL;
958: PetscInt numCoords,coneSize;
960: DMPlexGetConeSize(dm, c, &coneSize);
961: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
962: switch (coneSize) {
963: case 3:
964: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
965: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
966: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
967: break;
968: case 4:
969: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
970: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
971: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
972: PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
973: break;
974: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
975: }
976: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
977: }
978: PetscDrawFlush(draw);
979: PetscDrawPause(draw);
980: PetscDrawSave(draw);
981: return(0);
982: }
984: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
985: {
986: PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis;
987: PetscErrorCode ierr;
992: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
993: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
994: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
995: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
996: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
997: if (iascii) {
998: PetscViewerFormat format;
999: PetscViewerGetFormat(viewer, &format);
1000: if (format == PETSC_VIEWER_ASCII_GLVIS) {
1001: DMPlexView_GLVis(dm, viewer);
1002: } else {
1003: DMPlexView_Ascii(dm, viewer);
1004: }
1005: } else if (ishdf5) {
1006: #if defined(PETSC_HAVE_HDF5)
1007: PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
1008: DMPlexView_HDF5_Internal(dm, viewer);
1009: PetscViewerPopFormat(viewer);
1010: #else
1011: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1012: #endif
1013: } else if (isvtk) {
1014: DMPlexVTKWriteAll((PetscObject) dm,viewer);
1015: } else if (isdraw) {
1016: DMPlexView_Draw(dm, viewer);
1017: } else if (isglvis) {
1018: DMPlexView_GLVis(dm, viewer);
1019: }
1020: /* Optionally view the partition */
1021: PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1022: if (flg) {
1023: Vec ranks;
1024: DMPlexCreateRankField(dm, &ranks);
1025: VecView(ranks, viewer);
1026: VecDestroy(&ranks);
1027: }
1028: return(0);
1029: }
1031: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1032: {
1033: PetscBool isbinary, ishdf5;
1039: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
1040: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
1041: if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
1042: else if (ishdf5) {
1043: #if defined(PETSC_HAVE_HDF5)
1044: DMPlexLoad_HDF5_Internal(dm, viewer);
1045: #else
1046: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1047: #endif
1048: }
1049: return(0);
1050: }
1052: PetscErrorCode DMDestroy_Plex(DM dm)
1053: {
1054: DM_Plex *mesh = (DM_Plex*) dm->data;
1058: PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1059: PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1060: if (--mesh->refct > 0) return(0);
1061: PetscSectionDestroy(&mesh->coneSection);
1062: PetscFree(mesh->cones);
1063: PetscFree(mesh->coneOrientations);
1064: PetscSectionDestroy(&mesh->supportSection);
1065: PetscSectionDestroy(&mesh->subdomainSection);
1066: PetscFree(mesh->supports);
1067: PetscFree(mesh->facesTmp);
1068: PetscFree(mesh->tetgenOpts);
1069: PetscFree(mesh->triangleOpts);
1070: PetscPartitionerDestroy(&mesh->partitioner);
1071: DMLabelDestroy(&mesh->subpointMap);
1072: ISDestroy(&mesh->globalVertexNumbers);
1073: ISDestroy(&mesh->globalCellNumbers);
1074: PetscSectionDestroy(&mesh->anchorSection);
1075: ISDestroy(&mesh->anchorIS);
1076: PetscSectionDestroy(&mesh->parentSection);
1077: PetscFree(mesh->parents);
1078: PetscFree(mesh->childIDs);
1079: PetscSectionDestroy(&mesh->childSection);
1080: PetscFree(mesh->children);
1081: DMDestroy(&mesh->referenceTree);
1082: PetscGridHashDestroy(&mesh->lbox);
1083: /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1084: PetscFree(mesh);
1085: return(0);
1086: }
1088: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1089: {
1090: PetscSection sectionGlobal;
1091: PetscInt bs = -1, mbs;
1092: PetscInt localSize;
1093: PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1094: PetscErrorCode ierr;
1095: MatType mtype;
1096: ISLocalToGlobalMapping ltog;
1099: MatInitializePackage();
1100: mtype = dm->mattype;
1101: DMGetDefaultGlobalSection(dm, §ionGlobal);
1102: /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1103: PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1104: MatCreate(PetscObjectComm((PetscObject)dm), J);
1105: MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1106: MatSetType(*J, mtype);
1107: MatSetFromOptions(*J);
1108: MatGetBlockSize(*J, &mbs);
1109: if (mbs > 1) bs = mbs;
1110: PetscStrcmp(mtype, MATSHELL, &isShell);
1111: PetscStrcmp(mtype, MATBAIJ, &isBlock);
1112: PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1113: PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1114: PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1115: PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1116: PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1117: PetscStrcmp(mtype, MATIS, &isMatIS);
1118: if (!isShell) {
1119: PetscSection subSection;
1120: PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1121: PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1122: PetscInt pStart, pEnd, p, dof, cdof;
1124: /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
1125: if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
1126: PetscSection section;
1127: PetscInt size;
1129: DMGetDefaultSection(dm, §ion);
1130: PetscSectionGetStorageSize(section, &size);
1131: PetscMalloc1(size,<ogidx);
1132: DMPlexGetSubdomainSection(dm, &subSection);
1133: } else {
1134: DMGetLocalToGlobalMapping(dm,<og);
1135: }
1136: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1137: for (p = pStart, lsize = 0; p < pEnd; ++p) {
1138: PetscInt bdof;
1140: PetscSectionGetDof(sectionGlobal, p, &dof);
1141: PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1142: dof = dof < 0 ? -(dof+1) : dof;
1143: bdof = cdof && (dof-cdof) ? 1 : dof;
1144: if (dof) {
1145: if (bs < 0) {bs = bdof;}
1146: else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1147: }
1148: if (isMatIS) {
1149: PetscInt loff,c,off;
1150: PetscSectionGetOffset(subSection, p, &loff);
1151: PetscSectionGetOffset(sectionGlobal, p, &off);
1152: for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1153: }
1154: }
1155: /* Must have same blocksize on all procs (some might have no points) */
1156: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1157: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1158: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1159: else {bs = bsMinMax[0];}
1160: bs = bs < 0 ? 1 : bs;
1161: if (isMatIS) {
1162: PetscInt l;
1163: /* Must reduce indices by blocksize */
1164: if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1165: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, <og);
1166: }
1167: MatSetLocalToGlobalMapping(*J,ltog,ltog);
1168: if (isMatIS) {
1169: ISLocalToGlobalMappingDestroy(<og);
1170: }
1171: PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1172: DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1173: PetscFree4(dnz, onz, dnzu, onzu);
1174: }
1175: MatSetDM(*J, dm);
1176: return(0);
1177: }
1179: /*@
1180: DMPlexGetSubdomainSection - Returns the section associated with the subdomain
1182: Not collective
1184: Input Parameter:
1185: . mesh - The DMPlex
1187: Output Parameters:
1188: . subsection - The subdomain section
1190: Level: developer
1192: .seealso:
1193: @*/
1194: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1195: {
1196: DM_Plex *mesh = (DM_Plex*) dm->data;
1201: if (!mesh->subdomainSection) {
1202: PetscSection section;
1203: PetscSF sf;
1205: PetscSFCreate(PETSC_COMM_SELF,&sf);
1206: DMGetDefaultSection(dm,§ion);
1207: PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1208: PetscSFDestroy(&sf);
1209: }
1210: *subsection = mesh->subdomainSection;
1211: return(0);
1212: }
1214: /*@
1215: DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1217: Not collective
1219: Input Parameter:
1220: . mesh - The DMPlex
1222: Output Parameters:
1223: + pStart - The first mesh point
1224: - pEnd - The upper bound for mesh points
1226: Level: beginner
1228: .seealso: DMPlexCreate(), DMPlexSetChart()
1229: @*/
1230: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1231: {
1232: DM_Plex *mesh = (DM_Plex*) dm->data;
1237: PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1238: return(0);
1239: }
1241: /*@
1242: DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1244: Not collective
1246: Input Parameters:
1247: + mesh - The DMPlex
1248: . pStart - The first mesh point
1249: - pEnd - The upper bound for mesh points
1251: Output Parameters:
1253: Level: beginner
1255: .seealso: DMPlexCreate(), DMPlexGetChart()
1256: @*/
1257: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1258: {
1259: DM_Plex *mesh = (DM_Plex*) dm->data;
1264: PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1265: PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1266: return(0);
1267: }
1269: /*@
1270: DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
1272: Not collective
1274: Input Parameters:
1275: + mesh - The DMPlex
1276: - p - The point, which must lie in the chart set with DMPlexSetChart()
1278: Output Parameter:
1279: . size - The cone size for point p
1281: Level: beginner
1283: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1284: @*/
1285: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1286: {
1287: DM_Plex *mesh = (DM_Plex*) dm->data;
1293: PetscSectionGetDof(mesh->coneSection, p, size);
1294: return(0);
1295: }
1297: /*@
1298: DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
1300: Not collective
1302: Input Parameters:
1303: + mesh - The DMPlex
1304: . p - The point, which must lie in the chart set with DMPlexSetChart()
1305: - size - The cone size for point p
1307: Output Parameter:
1309: Note:
1310: This should be called after DMPlexSetChart().
1312: Level: beginner
1314: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1315: @*/
1316: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1317: {
1318: DM_Plex *mesh = (DM_Plex*) dm->data;
1323: PetscSectionSetDof(mesh->coneSection, p, size);
1325: mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1326: return(0);
1327: }
1329: /*@
1330: DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
1332: Not collective
1334: Input Parameters:
1335: + mesh - The DMPlex
1336: . p - The point, which must lie in the chart set with DMPlexSetChart()
1337: - size - The additional cone size for point p
1339: Output Parameter:
1341: Note:
1342: This should be called after DMPlexSetChart().
1344: Level: beginner
1346: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1347: @*/
1348: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1349: {
1350: DM_Plex *mesh = (DM_Plex*) dm->data;
1351: PetscInt csize;
1356: PetscSectionAddDof(mesh->coneSection, p, size);
1357: PetscSectionGetDof(mesh->coneSection, p, &csize);
1359: mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1360: return(0);
1361: }
1363: /*@C
1364: DMPlexGetCone - Return the points on the in-edges for this point in the DAG
1366: Not collective
1368: Input Parameters:
1369: + mesh - The DMPlex
1370: - p - The point, which must lie in the chart set with DMPlexSetChart()
1372: Output Parameter:
1373: . cone - An array of points which are on the in-edges for point p
1375: Level: beginner
1377: Fortran Notes:
1378: Since it returns an array, this routine is only available in Fortran 90, and you must
1379: include petsc.h90 in your code.
1381: You must also call DMPlexRestoreCone() after you finish using the returned array.
1383: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1384: @*/
1385: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1386: {
1387: DM_Plex *mesh = (DM_Plex*) dm->data;
1388: PetscInt off;
1394: PetscSectionGetOffset(mesh->coneSection, p, &off);
1395: *cone = &mesh->cones[off];
1396: return(0);
1397: }
1399: /*@
1400: DMPlexSetCone - Set the points on the in-edges for this point in the DAG
1402: Not collective
1404: Input Parameters:
1405: + mesh - The DMPlex
1406: . p - The point, which must lie in the chart set with DMPlexSetChart()
1407: - cone - An array of points which are on the in-edges for point p
1409: Output Parameter:
1411: Note:
1412: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1414: Level: beginner
1416: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1417: @*/
1418: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1419: {
1420: DM_Plex *mesh = (DM_Plex*) dm->data;
1421: PetscInt pStart, pEnd;
1422: PetscInt dof, off, c;
1427: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1428: PetscSectionGetDof(mesh->coneSection, p, &dof);
1430: PetscSectionGetOffset(mesh->coneSection, p, &off);
1431: 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);
1432: for (c = 0; c < dof; ++c) {
1433: 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);
1434: mesh->cones[off+c] = cone[c];
1435: }
1436: return(0);
1437: }
1439: /*@C
1440: DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
1442: Not collective
1444: Input Parameters:
1445: + mesh - The DMPlex
1446: - p - The point, which must lie in the chart set with DMPlexSetChart()
1448: Output Parameter:
1449: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1450: integer giving the prescription for cone traversal. If it is negative, the cone is
1451: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1452: the index of the cone point on which to start.
1454: Level: beginner
1456: Fortran Notes:
1457: Since it returns an array, this routine is only available in Fortran 90, and you must
1458: include petsc.h90 in your code.
1460: You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1462: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1463: @*/
1464: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1465: {
1466: DM_Plex *mesh = (DM_Plex*) dm->data;
1467: PetscInt off;
1472: #if defined(PETSC_USE_DEBUG)
1473: {
1474: PetscInt dof;
1475: PetscSectionGetDof(mesh->coneSection, p, &dof);
1477: }
1478: #endif
1479: PetscSectionGetOffset(mesh->coneSection, p, &off);
1481: *coneOrientation = &mesh->coneOrientations[off];
1482: return(0);
1483: }
1485: /*@
1486: DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
1488: Not collective
1490: Input Parameters:
1491: + mesh - The DMPlex
1492: . p - The point, which must lie in the chart set with DMPlexSetChart()
1493: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1494: integer giving the prescription for cone traversal. If it is negative, the cone is
1495: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1496: the index of the cone point on which to start.
1498: Output Parameter:
1500: Note:
1501: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1503: Level: beginner
1505: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1506: @*/
1507: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1508: {
1509: DM_Plex *mesh = (DM_Plex*) dm->data;
1510: PetscInt pStart, pEnd;
1511: PetscInt dof, off, c;
1516: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1517: PetscSectionGetDof(mesh->coneSection, p, &dof);
1519: PetscSectionGetOffset(mesh->coneSection, p, &off);
1520: 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);
1521: for (c = 0; c < dof; ++c) {
1522: PetscInt cdof, o = coneOrientation[c];
1524: PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1525: 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);
1526: mesh->coneOrientations[off+c] = o;
1527: }
1528: return(0);
1529: }
1531: /*@
1532: DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
1534: Not collective
1536: Input Parameters:
1537: + mesh - The DMPlex
1538: . p - The point, which must lie in the chart set with DMPlexSetChart()
1539: . conePos - The local index in the cone where the point should be put
1540: - conePoint - The mesh point to insert
1542: Level: beginner
1544: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1545: @*/
1546: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1547: {
1548: DM_Plex *mesh = (DM_Plex*) dm->data;
1549: PetscInt pStart, pEnd;
1550: PetscInt dof, off;
1555: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1556: 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);
1557: 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);
1558: PetscSectionGetDof(mesh->coneSection, p, &dof);
1559: PetscSectionGetOffset(mesh->coneSection, p, &off);
1560: 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);
1561: mesh->cones[off+conePos] = conePoint;
1562: return(0);
1563: }
1565: /*@
1566: DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
1568: Not collective
1570: Input Parameters:
1571: + mesh - The DMPlex
1572: . p - The point, which must lie in the chart set with DMPlexSetChart()
1573: . conePos - The local index in the cone where the point should be put
1574: - coneOrientation - The point orientation to insert
1576: Level: beginner
1578: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1579: @*/
1580: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1581: {
1582: DM_Plex *mesh = (DM_Plex*) dm->data;
1583: PetscInt pStart, pEnd;
1584: PetscInt dof, off;
1589: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1590: 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);
1591: PetscSectionGetDof(mesh->coneSection, p, &dof);
1592: PetscSectionGetOffset(mesh->coneSection, p, &off);
1593: 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);
1594: mesh->coneOrientations[off+conePos] = coneOrientation;
1595: return(0);
1596: }
1598: /*@
1599: DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
1601: Not collective
1603: Input Parameters:
1604: + mesh - The DMPlex
1605: - p - The point, which must lie in the chart set with DMPlexSetChart()
1607: Output Parameter:
1608: . size - The support size for point p
1610: Level: beginner
1612: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1613: @*/
1614: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1615: {
1616: DM_Plex *mesh = (DM_Plex*) dm->data;
1622: PetscSectionGetDof(mesh->supportSection, p, size);
1623: return(0);
1624: }
1626: /*@
1627: DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
1629: Not collective
1631: Input Parameters:
1632: + mesh - The DMPlex
1633: . p - The point, which must lie in the chart set with DMPlexSetChart()
1634: - size - The support size for point p
1636: Output Parameter:
1638: Note:
1639: This should be called after DMPlexSetChart().
1641: Level: beginner
1643: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1644: @*/
1645: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1646: {
1647: DM_Plex *mesh = (DM_Plex*) dm->data;
1652: PetscSectionSetDof(mesh->supportSection, p, size);
1654: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1655: return(0);
1656: }
1658: /*@C
1659: DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
1661: Not collective
1663: Input Parameters:
1664: + mesh - The DMPlex
1665: - p - The point, which must lie in the chart set with DMPlexSetChart()
1667: Output Parameter:
1668: . support - An array of points which are on the out-edges for point p
1670: Level: beginner
1672: Fortran Notes:
1673: Since it returns an array, this routine is only available in Fortran 90, and you must
1674: include petsc.h90 in your code.
1676: You must also call DMPlexRestoreSupport() after you finish using the returned array.
1678: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1679: @*/
1680: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1681: {
1682: DM_Plex *mesh = (DM_Plex*) dm->data;
1683: PetscInt off;
1689: PetscSectionGetOffset(mesh->supportSection, p, &off);
1690: *support = &mesh->supports[off];
1691: return(0);
1692: }
1694: /*@
1695: DMPlexSetSupport - Set the points on the out-edges for this point in the DAG
1697: Not collective
1699: Input Parameters:
1700: + mesh - The DMPlex
1701: . p - The point, which must lie in the chart set with DMPlexSetChart()
1702: - support - An array of points which are on the in-edges for point p
1704: Output Parameter:
1706: Note:
1707: This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1709: Level: beginner
1711: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1712: @*/
1713: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1714: {
1715: DM_Plex *mesh = (DM_Plex*) dm->data;
1716: PetscInt pStart, pEnd;
1717: PetscInt dof, off, c;
1722: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1723: PetscSectionGetDof(mesh->supportSection, p, &dof);
1725: PetscSectionGetOffset(mesh->supportSection, p, &off);
1726: 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);
1727: for (c = 0; c < dof; ++c) {
1728: 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);
1729: mesh->supports[off+c] = support[c];
1730: }
1731: return(0);
1732: }
1734: /*@
1735: DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
1737: Not collective
1739: Input Parameters:
1740: + mesh - The DMPlex
1741: . p - The point, which must lie in the chart set with DMPlexSetChart()
1742: . supportPos - The local index in the cone where the point should be put
1743: - supportPoint - The mesh point to insert
1745: Level: beginner
1747: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1748: @*/
1749: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1750: {
1751: DM_Plex *mesh = (DM_Plex*) dm->data;
1752: PetscInt pStart, pEnd;
1753: PetscInt dof, off;
1758: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1759: PetscSectionGetDof(mesh->supportSection, p, &dof);
1760: PetscSectionGetOffset(mesh->supportSection, p, &off);
1761: 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);
1762: 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);
1763: 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);
1764: mesh->supports[off+supportPos] = supportPoint;
1765: return(0);
1766: }
1768: /*@C
1769: DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
1771: Not collective
1773: Input Parameters:
1774: + mesh - The DMPlex
1775: . p - The point, which must lie in the chart set with DMPlexSetChart()
1776: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
1777: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1779: Output Parameters:
1780: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1781: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1783: Note:
1784: If using internal storage (points is NULL on input), each call overwrites the last output.
1786: Fortran Notes:
1787: Since it returns an array, this routine is only available in Fortran 90, and you must
1788: include petsc.h90 in your code.
1790: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1792: Level: beginner
1794: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1795: @*/
1796: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1797: {
1798: DM_Plex *mesh = (DM_Plex*) dm->data;
1799: PetscInt *closure, *fifo;
1800: const PetscInt *tmp = NULL, *tmpO = NULL;
1801: PetscInt tmpSize, t;
1802: PetscInt depth = 0, maxSize;
1803: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
1804: PetscErrorCode ierr;
1808: DMPlexGetDepth(dm, &depth);
1809: /* This is only 1-level */
1810: if (useCone) {
1811: DMPlexGetConeSize(dm, p, &tmpSize);
1812: DMPlexGetCone(dm, p, &tmp);
1813: DMPlexGetConeOrientation(dm, p, &tmpO);
1814: } else {
1815: DMPlexGetSupportSize(dm, p, &tmpSize);
1816: DMPlexGetSupport(dm, p, &tmp);
1817: }
1818: if (depth == 1) {
1819: if (*points) {
1820: closure = *points;
1821: } else {
1822: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1823: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1824: }
1825: closure[0] = p; closure[1] = 0;
1826: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1827: closure[closureSize] = tmp[t];
1828: closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1829: }
1830: if (numPoints) *numPoints = closureSize/2;
1831: if (points) *points = closure;
1832: return(0);
1833: }
1834: {
1835: PetscInt c, coneSeries, s,supportSeries;
1837: c = mesh->maxConeSize;
1838: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1839: s = mesh->maxSupportSize;
1840: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1841: maxSize = 2*PetscMax(coneSeries,supportSeries);
1842: }
1843: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
1844: if (*points) {
1845: closure = *points;
1846: } else {
1847: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1848: }
1849: closure[0] = p; closure[1] = 0;
1850: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1851: const PetscInt cp = tmp[t];
1852: const PetscInt co = tmpO ? tmpO[t] : 0;
1854: closure[closureSize] = cp;
1855: closure[closureSize+1] = co;
1856: fifo[fifoSize] = cp;
1857: fifo[fifoSize+1] = co;
1858: }
1859: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1860: while (fifoSize - fifoStart) {
1861: const PetscInt q = fifo[fifoStart];
1862: const PetscInt o = fifo[fifoStart+1];
1863: const PetscInt rev = o >= 0 ? 0 : 1;
1864: const PetscInt off = rev ? -(o+1) : o;
1866: if (useCone) {
1867: DMPlexGetConeSize(dm, q, &tmpSize);
1868: DMPlexGetCone(dm, q, &tmp);
1869: DMPlexGetConeOrientation(dm, q, &tmpO);
1870: } else {
1871: DMPlexGetSupportSize(dm, q, &tmpSize);
1872: DMPlexGetSupport(dm, q, &tmp);
1873: tmpO = NULL;
1874: }
1875: for (t = 0; t < tmpSize; ++t) {
1876: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
1877: const PetscInt cp = tmp[i];
1878: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1879: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1880: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1881: PetscInt co = tmpO ? tmpO[i] : 0;
1882: PetscInt c;
1884: if (rev) {
1885: PetscInt childSize, coff;
1886: DMPlexGetConeSize(dm, cp, &childSize);
1887: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1888: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1889: }
1890: /* Check for duplicate */
1891: for (c = 0; c < closureSize; c += 2) {
1892: if (closure[c] == cp) break;
1893: }
1894: if (c == closureSize) {
1895: closure[closureSize] = cp;
1896: closure[closureSize+1] = co;
1897: fifo[fifoSize] = cp;
1898: fifo[fifoSize+1] = co;
1899: closureSize += 2;
1900: fifoSize += 2;
1901: }
1902: }
1903: fifoStart += 2;
1904: }
1905: if (numPoints) *numPoints = closureSize/2;
1906: if (points) *points = closure;
1907: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
1908: return(0);
1909: }
1911: /*@C
1912: 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
1914: Not collective
1916: Input Parameters:
1917: + mesh - The DMPlex
1918: . p - The point, which must lie in the chart set with DMPlexSetChart()
1919: . orientation - The orientation of the point
1920: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
1921: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1923: Output Parameters:
1924: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1925: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1927: Note:
1928: If using internal storage (points is NULL on input), each call overwrites the last output.
1930: Fortran Notes:
1931: Since it returns an array, this routine is only available in Fortran 90, and you must
1932: include petsc.h90 in your code.
1934: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1936: Level: beginner
1938: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1939: @*/
1940: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1941: {
1942: DM_Plex *mesh = (DM_Plex*) dm->data;
1943: PetscInt *closure, *fifo;
1944: const PetscInt *tmp = NULL, *tmpO = NULL;
1945: PetscInt tmpSize, t;
1946: PetscInt depth = 0, maxSize;
1947: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
1948: PetscErrorCode ierr;
1952: DMPlexGetDepth(dm, &depth);
1953: /* This is only 1-level */
1954: if (useCone) {
1955: DMPlexGetConeSize(dm, p, &tmpSize);
1956: DMPlexGetCone(dm, p, &tmp);
1957: DMPlexGetConeOrientation(dm, p, &tmpO);
1958: } else {
1959: DMPlexGetSupportSize(dm, p, &tmpSize);
1960: DMPlexGetSupport(dm, p, &tmp);
1961: }
1962: if (depth == 1) {
1963: if (*points) {
1964: closure = *points;
1965: } else {
1966: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1967: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1968: }
1969: closure[0] = p; closure[1] = ornt;
1970: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1971: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1972: closure[closureSize] = tmp[i];
1973: closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1974: }
1975: if (numPoints) *numPoints = closureSize/2;
1976: if (points) *points = closure;
1977: return(0);
1978: }
1979: {
1980: PetscInt c, coneSeries, s,supportSeries;
1982: c = mesh->maxConeSize;
1983: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1984: s = mesh->maxSupportSize;
1985: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1986: maxSize = 2*PetscMax(coneSeries,supportSeries);
1987: }
1988: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
1989: if (*points) {
1990: closure = *points;
1991: } else {
1992: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1993: }
1994: closure[0] = p; closure[1] = ornt;
1995: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1996: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1997: const PetscInt cp = tmp[i];
1998: PetscInt co = tmpO ? tmpO[i] : 0;
2000: if (ornt < 0) {
2001: PetscInt childSize, coff;
2002: DMPlexGetConeSize(dm, cp, &childSize);
2003: coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2004: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2005: }
2006: closure[closureSize] = cp;
2007: closure[closureSize+1] = co;
2008: fifo[fifoSize] = cp;
2009: fifo[fifoSize+1] = co;
2010: }
2011: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2012: while (fifoSize - fifoStart) {
2013: const PetscInt q = fifo[fifoStart];
2014: const PetscInt o = fifo[fifoStart+1];
2015: const PetscInt rev = o >= 0 ? 0 : 1;
2016: const PetscInt off = rev ? -(o+1) : o;
2018: if (useCone) {
2019: DMPlexGetConeSize(dm, q, &tmpSize);
2020: DMPlexGetCone(dm, q, &tmp);
2021: DMPlexGetConeOrientation(dm, q, &tmpO);
2022: } else {
2023: DMPlexGetSupportSize(dm, q, &tmpSize);
2024: DMPlexGetSupport(dm, q, &tmp);
2025: tmpO = NULL;
2026: }
2027: for (t = 0; t < tmpSize; ++t) {
2028: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
2029: const PetscInt cp = tmp[i];
2030: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2031: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2032: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2033: PetscInt co = tmpO ? tmpO[i] : 0;
2034: PetscInt c;
2036: if (rev) {
2037: PetscInt childSize, coff;
2038: DMPlexGetConeSize(dm, cp, &childSize);
2039: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2040: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2041: }
2042: /* Check for duplicate */
2043: for (c = 0; c < closureSize; c += 2) {
2044: if (closure[c] == cp) break;
2045: }
2046: if (c == closureSize) {
2047: closure[closureSize] = cp;
2048: closure[closureSize+1] = co;
2049: fifo[fifoSize] = cp;
2050: fifo[fifoSize+1] = co;
2051: closureSize += 2;
2052: fifoSize += 2;
2053: }
2054: }
2055: fifoStart += 2;
2056: }
2057: if (numPoints) *numPoints = closureSize/2;
2058: if (points) *points = closure;
2059: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2060: return(0);
2061: }
2063: /*@C
2064: DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
2066: Not collective
2068: Input Parameters:
2069: + mesh - The DMPlex
2070: . p - The point, which must lie in the chart set with DMPlexSetChart()
2071: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2072: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
2073: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
2075: Note:
2076: If not using internal storage (points is not NULL on input), this call is unnecessary
2078: Fortran Notes:
2079: Since it returns an array, this routine is only available in Fortran 90, and you must
2080: include petsc.h90 in your code.
2082: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2084: Level: beginner
2086: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2087: @*/
2088: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2089: {
2096: DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2097: if (numPoints) *numPoints = 0;
2098: return(0);
2099: }
2101: /*@
2102: DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
2104: Not collective
2106: Input Parameter:
2107: . mesh - The DMPlex
2109: Output Parameters:
2110: + maxConeSize - The maximum number of in-edges
2111: - maxSupportSize - The maximum number of out-edges
2113: Level: beginner
2115: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2116: @*/
2117: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2118: {
2119: DM_Plex *mesh = (DM_Plex*) dm->data;
2123: if (maxConeSize) *maxConeSize = mesh->maxConeSize;
2124: if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2125: return(0);
2126: }
2128: PetscErrorCode DMSetUp_Plex(DM dm)
2129: {
2130: DM_Plex *mesh = (DM_Plex*) dm->data;
2131: PetscInt size;
2136: PetscSectionSetUp(mesh->coneSection);
2137: PetscSectionGetStorageSize(mesh->coneSection, &size);
2138: PetscMalloc1(size, &mesh->cones);
2139: PetscCalloc1(size, &mesh->coneOrientations);
2140: if (mesh->maxSupportSize) {
2141: PetscSectionSetUp(mesh->supportSection);
2142: PetscSectionGetStorageSize(mesh->supportSection, &size);
2143: PetscMalloc1(size, &mesh->supports);
2144: }
2145: return(0);
2146: }
2148: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2149: {
2153: if (subdm) {DMClone(dm, subdm);}
2154: DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2155: if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2156: if (dm->useNatural && dm->sfMigration) {
2157: PetscSF sfMigrationInv,sfNatural;
2158: PetscSection section, sectionSeq;
2160: (*subdm)->sfMigration = dm->sfMigration;
2161: PetscObjectReference((PetscObject) dm->sfMigration);
2162: DMGetDefaultSection((*subdm), §ion);
2163: PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2164: PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq);
2165: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2166:
2167: DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2168: (*subdm)->sfNatural = sfNatural;
2169: PetscSectionDestroy(§ionSeq);
2170: PetscSFDestroy(&sfMigrationInv);
2171: }
2172: return(0);
2173: }
2175: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2176: {
2178: PetscInt i = 0;
2181: if (superdm) {DMClone(dms[0], superdm);}
2182: DMCreateSuperDM_Section_Private(dms, len, is, superdm);
2183: (*superdm)->useNatural = PETSC_FALSE;
2184: for (i = 0; i < len; i++){
2185: if (dms[i]->useNatural && dms[i]->sfMigration) {
2186: PetscSF sfMigrationInv,sfNatural;
2187: PetscSection section, sectionSeq;
2189: (*superdm)->sfMigration = dms[i]->sfMigration;
2190: PetscObjectReference((PetscObject) dms[i]->sfMigration);
2191: (*superdm)->useNatural = PETSC_TRUE;
2192: DMGetDefaultSection((*superdm), §ion);
2193: PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2194: PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq);
2195: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2196:
2197: DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2198: (*superdm)->sfNatural = sfNatural;
2199: PetscSectionDestroy(§ionSeq);
2200: PetscSFDestroy(&sfMigrationInv);
2201: break;
2202: }
2203: }
2204: return(0);
2205: }
2207: /*@
2208: DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
2210: Not collective
2212: Input Parameter:
2213: . mesh - The DMPlex
2215: Output Parameter:
2217: Note:
2218: This should be called after all calls to DMPlexSetCone()
2220: Level: beginner
2222: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2223: @*/
2224: PetscErrorCode DMPlexSymmetrize(DM dm)
2225: {
2226: DM_Plex *mesh = (DM_Plex*) dm->data;
2227: PetscInt *offsets;
2228: PetscInt supportSize;
2229: PetscInt pStart, pEnd, p;
2234: if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2235: /* Calculate support sizes */
2236: DMPlexGetChart(dm, &pStart, &pEnd);
2237: for (p = pStart; p < pEnd; ++p) {
2238: PetscInt dof, off, c;
2240: PetscSectionGetDof(mesh->coneSection, p, &dof);
2241: PetscSectionGetOffset(mesh->coneSection, p, &off);
2242: for (c = off; c < off+dof; ++c) {
2243: PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2244: }
2245: }
2246: for (p = pStart; p < pEnd; ++p) {
2247: PetscInt dof;
2249: PetscSectionGetDof(mesh->supportSection, p, &dof);
2251: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2252: }
2253: PetscSectionSetUp(mesh->supportSection);
2254: /* Calculate supports */
2255: PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2256: PetscMalloc1(supportSize, &mesh->supports);
2257: PetscCalloc1(pEnd - pStart, &offsets);
2258: for (p = pStart; p < pEnd; ++p) {
2259: PetscInt dof, off, c;
2261: PetscSectionGetDof(mesh->coneSection, p, &dof);
2262: PetscSectionGetOffset(mesh->coneSection, p, &off);
2263: for (c = off; c < off+dof; ++c) {
2264: const PetscInt q = mesh->cones[c];
2265: PetscInt offS;
2267: PetscSectionGetOffset(mesh->supportSection, q, &offS);
2269: mesh->supports[offS+offsets[q]] = p;
2270: ++offsets[q];
2271: }
2272: }
2273: PetscFree(offsets);
2274: return(0);
2275: }
2277: /*@
2278: DMPlexStratify - The DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2279: can be illustrated by a Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2280: same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2281: the DAG.
2283: Collective on dm
2285: Input Parameter:
2286: . mesh - The DMPlex
2288: Output Parameter:
2290: Notes:
2291: Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2292: 1 for edges, and so on. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2293: manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed
2294: via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1.
2296: DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
2298: Level: beginner
2300: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2301: @*/
2302: PetscErrorCode DMPlexStratify(DM dm)
2303: {
2304: DM_Plex *mesh = (DM_Plex*) dm->data;
2305: DMLabel label;
2306: PetscInt pStart, pEnd, p;
2307: PetscInt numRoots = 0, numLeaves = 0;
2312: PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2313: /* Calculate depth */
2314: DMPlexGetChart(dm, &pStart, &pEnd);
2315: DMCreateLabel(dm, "depth");
2316: DMPlexGetDepthLabel(dm, &label);
2317: /* Initialize roots and count leaves */
2318: for (p = pStart; p < pEnd; ++p) {
2319: PetscInt coneSize, supportSize;
2321: DMPlexGetConeSize(dm, p, &coneSize);
2322: DMPlexGetSupportSize(dm, p, &supportSize);
2323: if (!coneSize && supportSize) {
2324: ++numRoots;
2325: DMLabelSetValue(label, p, 0);
2326: } else if (!supportSize && coneSize) {
2327: ++numLeaves;
2328: } else if (!supportSize && !coneSize) {
2329: /* Isolated points */
2330: DMLabelSetValue(label, p, 0);
2331: }
2332: }
2333: if (numRoots + numLeaves == (pEnd - pStart)) {
2334: for (p = pStart; p < pEnd; ++p) {
2335: PetscInt coneSize, supportSize;
2337: DMPlexGetConeSize(dm, p, &coneSize);
2338: DMPlexGetSupportSize(dm, p, &supportSize);
2339: if (!supportSize && coneSize) {
2340: DMLabelSetValue(label, p, 1);
2341: }
2342: }
2343: } else {
2344: IS pointIS;
2345: PetscInt numPoints = 0, level = 0;
2347: DMLabelGetStratumIS(label, level, &pointIS);
2348: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2349: while (numPoints) {
2350: const PetscInt *points;
2351: const PetscInt newLevel = level+1;
2353: ISGetIndices(pointIS, &points);
2354: for (p = 0; p < numPoints; ++p) {
2355: const PetscInt point = points[p];
2356: const PetscInt *support;
2357: PetscInt supportSize, s;
2359: DMPlexGetSupportSize(dm, point, &supportSize);
2360: DMPlexGetSupport(dm, point, &support);
2361: for (s = 0; s < supportSize; ++s) {
2362: DMLabelSetValue(label, support[s], newLevel);
2363: }
2364: }
2365: ISRestoreIndices(pointIS, &points);
2366: ++level;
2367: ISDestroy(&pointIS);
2368: DMLabelGetStratumIS(label, level, &pointIS);
2369: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2370: else {numPoints = 0;}
2371: }
2372: ISDestroy(&pointIS);
2373: }
2374: { /* just in case there is an empty process */
2375: PetscInt numValues, maxValues = 0, v;
2377: DMLabelGetNumValues(label,&numValues);
2378: for (v = 0; v < numValues; v++) {
2379: IS pointIS;
2381: DMLabelGetStratumIS(label, v, &pointIS);
2382: if (pointIS) {
2383: PetscInt min, max, numPoints;
2384: PetscInt start;
2385: PetscBool contig;
2387: ISGetLocalSize(pointIS, &numPoints);
2388: ISGetMinMax(pointIS, &min, &max);
2389: ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2390: if (start == 0 && contig) {
2391: ISDestroy(&pointIS);
2392: ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2393: DMLabelSetStratumIS(label, v, pointIS);
2394: }
2395: }
2396: ISDestroy(&pointIS);
2397: }
2398: MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2399: for (v = numValues; v < maxValues; v++) {
2400: DMLabelAddStratum(label,v);
2401: }
2402: }
2404: DMLabelGetState(label, &mesh->depthState);
2405: PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2406: return(0);
2407: }
2409: /*@C
2410: DMPlexGetJoin - Get an array for the join of the set of points
2412: Not Collective
2414: Input Parameters:
2415: + dm - The DMPlex object
2416: . numPoints - The number of input points for the join
2417: - points - The input points
2419: Output Parameters:
2420: + numCoveredPoints - The number of points in the join
2421: - coveredPoints - The points in the join
2423: Level: intermediate
2425: Note: Currently, this is restricted to a single level join
2427: Fortran Notes:
2428: Since it returns an array, this routine is only available in Fortran 90, and you must
2429: include petsc.h90 in your code.
2431: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2433: .keywords: mesh
2434: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2435: @*/
2436: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2437: {
2438: DM_Plex *mesh = (DM_Plex*) dm->data;
2439: PetscInt *join[2];
2440: PetscInt joinSize, i = 0;
2441: PetscInt dof, off, p, c, m;
2449: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2450: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2451: /* Copy in support of first point */
2452: PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2453: PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2454: for (joinSize = 0; joinSize < dof; ++joinSize) {
2455: join[i][joinSize] = mesh->supports[off+joinSize];
2456: }
2457: /* Check each successive support */
2458: for (p = 1; p < numPoints; ++p) {
2459: PetscInt newJoinSize = 0;
2461: PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2462: PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2463: for (c = 0; c < dof; ++c) {
2464: const PetscInt point = mesh->supports[off+c];
2466: for (m = 0; m < joinSize; ++m) {
2467: if (point == join[i][m]) {
2468: join[1-i][newJoinSize++] = point;
2469: break;
2470: }
2471: }
2472: }
2473: joinSize = newJoinSize;
2474: i = 1-i;
2475: }
2476: *numCoveredPoints = joinSize;
2477: *coveredPoints = join[i];
2478: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2479: return(0);
2480: }
2482: /*@C
2483: DMPlexRestoreJoin - Restore an array for the join of the set of points
2485: Not Collective
2487: Input Parameters:
2488: + dm - The DMPlex object
2489: . numPoints - The number of input points for the join
2490: - points - The input points
2492: Output Parameters:
2493: + numCoveredPoints - The number of points in the join
2494: - coveredPoints - The points in the join
2496: Fortran Notes:
2497: Since it returns an array, this routine is only available in Fortran 90, and you must
2498: include petsc.h90 in your code.
2500: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2502: Level: intermediate
2504: .keywords: mesh
2505: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2506: @*/
2507: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2508: {
2516: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2517: if (numCoveredPoints) *numCoveredPoints = 0;
2518: return(0);
2519: }
2521: /*@C
2522: DMPlexGetFullJoin - Get an array for the join of the set of points
2524: Not Collective
2526: Input Parameters:
2527: + dm - The DMPlex object
2528: . numPoints - The number of input points for the join
2529: - points - The input points
2531: Output Parameters:
2532: + numCoveredPoints - The number of points in the join
2533: - coveredPoints - The points in the join
2535: Fortran Notes:
2536: Since it returns an array, this routine is only available in Fortran 90, and you must
2537: include petsc.h90 in your code.
2539: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2541: Level: intermediate
2543: .keywords: mesh
2544: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2545: @*/
2546: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2547: {
2548: DM_Plex *mesh = (DM_Plex*) dm->data;
2549: PetscInt *offsets, **closures;
2550: PetscInt *join[2];
2551: PetscInt depth = 0, maxSize, joinSize = 0, i = 0;
2552: PetscInt p, d, c, m, ms;
2561: DMPlexGetDepth(dm, &depth);
2562: PetscCalloc1(numPoints, &closures);
2563: DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2564: ms = mesh->maxSupportSize;
2565: maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2566: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2567: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);
2569: for (p = 0; p < numPoints; ++p) {
2570: PetscInt closureSize;
2572: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);
2574: offsets[p*(depth+2)+0] = 0;
2575: for (d = 0; d < depth+1; ++d) {
2576: PetscInt pStart, pEnd, i;
2578: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2579: for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2580: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2581: offsets[p*(depth+2)+d+1] = i;
2582: break;
2583: }
2584: }
2585: if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2586: }
2587: 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);
2588: }
2589: for (d = 0; d < depth+1; ++d) {
2590: PetscInt dof;
2592: /* Copy in support of first point */
2593: dof = offsets[d+1] - offsets[d];
2594: for (joinSize = 0; joinSize < dof; ++joinSize) {
2595: join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2596: }
2597: /* Check each successive cone */
2598: for (p = 1; p < numPoints && joinSize; ++p) {
2599: PetscInt newJoinSize = 0;
2601: dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2602: for (c = 0; c < dof; ++c) {
2603: const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2605: for (m = 0; m < joinSize; ++m) {
2606: if (point == join[i][m]) {
2607: join[1-i][newJoinSize++] = point;
2608: break;
2609: }
2610: }
2611: }
2612: joinSize = newJoinSize;
2613: i = 1-i;
2614: }
2615: if (joinSize) break;
2616: }
2617: *numCoveredPoints = joinSize;
2618: *coveredPoints = join[i];
2619: for (p = 0; p < numPoints; ++p) {
2620: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2621: }
2622: PetscFree(closures);
2623: DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2624: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2625: return(0);
2626: }
2628: /*@C
2629: DMPlexGetMeet - Get an array for the meet of the set of points
2631: Not Collective
2633: Input Parameters:
2634: + dm - The DMPlex object
2635: . numPoints - The number of input points for the meet
2636: - points - The input points
2638: Output Parameters:
2639: + numCoveredPoints - The number of points in the meet
2640: - coveredPoints - The points in the meet
2642: Level: intermediate
2644: Note: Currently, this is restricted to a single level meet
2646: Fortran Notes:
2647: Since it returns an array, this routine is only available in Fortran 90, and you must
2648: include petsc.h90 in your code.
2650: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2652: .keywords: mesh
2653: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2654: @*/
2655: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2656: {
2657: DM_Plex *mesh = (DM_Plex*) dm->data;
2658: PetscInt *meet[2];
2659: PetscInt meetSize, i = 0;
2660: PetscInt dof, off, p, c, m;
2668: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2669: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2670: /* Copy in cone of first point */
2671: PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2672: PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2673: for (meetSize = 0; meetSize < dof; ++meetSize) {
2674: meet[i][meetSize] = mesh->cones[off+meetSize];
2675: }
2676: /* Check each successive cone */
2677: for (p = 1; p < numPoints; ++p) {
2678: PetscInt newMeetSize = 0;
2680: PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2681: PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2682: for (c = 0; c < dof; ++c) {
2683: const PetscInt point = mesh->cones[off+c];
2685: for (m = 0; m < meetSize; ++m) {
2686: if (point == meet[i][m]) {
2687: meet[1-i][newMeetSize++] = point;
2688: break;
2689: }
2690: }
2691: }
2692: meetSize = newMeetSize;
2693: i = 1-i;
2694: }
2695: *numCoveringPoints = meetSize;
2696: *coveringPoints = meet[i];
2697: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2698: return(0);
2699: }
2701: /*@C
2702: DMPlexRestoreMeet - Restore an array for the meet of the set of points
2704: Not Collective
2706: Input Parameters:
2707: + dm - The DMPlex object
2708: . numPoints - The number of input points for the meet
2709: - points - The input points
2711: Output Parameters:
2712: + numCoveredPoints - The number of points in the meet
2713: - coveredPoints - The points in the meet
2715: Level: intermediate
2717: Fortran Notes:
2718: Since it returns an array, this routine is only available in Fortran 90, and you must
2719: include petsc.h90 in your code.
2721: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2723: .keywords: mesh
2724: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2725: @*/
2726: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2727: {
2735: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2736: if (numCoveredPoints) *numCoveredPoints = 0;
2737: return(0);
2738: }
2740: /*@C
2741: DMPlexGetFullMeet - Get an array for the meet of the set of points
2743: Not Collective
2745: Input Parameters:
2746: + dm - The DMPlex object
2747: . numPoints - The number of input points for the meet
2748: - points - The input points
2750: Output Parameters:
2751: + numCoveredPoints - The number of points in the meet
2752: - coveredPoints - The points in the meet
2754: Level: intermediate
2756: Fortran Notes:
2757: Since it returns an array, this routine is only available in Fortran 90, and you must
2758: include petsc.h90 in your code.
2760: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2762: .keywords: mesh
2763: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2764: @*/
2765: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2766: {
2767: DM_Plex *mesh = (DM_Plex*) dm->data;
2768: PetscInt *offsets, **closures;
2769: PetscInt *meet[2];
2770: PetscInt height = 0, maxSize, meetSize = 0, i = 0;
2771: PetscInt p, h, c, m, mc;
2780: DMPlexGetDepth(dm, &height);
2781: PetscMalloc1(numPoints, &closures);
2782: DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2783: mc = mesh->maxConeSize;
2784: maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2785: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
2786: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);
2788: for (p = 0; p < numPoints; ++p) {
2789: PetscInt closureSize;
2791: DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);
2793: offsets[p*(height+2)+0] = 0;
2794: for (h = 0; h < height+1; ++h) {
2795: PetscInt pStart, pEnd, i;
2797: DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2798: for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2799: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2800: offsets[p*(height+2)+h+1] = i;
2801: break;
2802: }
2803: }
2804: if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2805: }
2806: 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);
2807: }
2808: for (h = 0; h < height+1; ++h) {
2809: PetscInt dof;
2811: /* Copy in cone of first point */
2812: dof = offsets[h+1] - offsets[h];
2813: for (meetSize = 0; meetSize < dof; ++meetSize) {
2814: meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2815: }
2816: /* Check each successive cone */
2817: for (p = 1; p < numPoints && meetSize; ++p) {
2818: PetscInt newMeetSize = 0;
2820: dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2821: for (c = 0; c < dof; ++c) {
2822: const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2824: for (m = 0; m < meetSize; ++m) {
2825: if (point == meet[i][m]) {
2826: meet[1-i][newMeetSize++] = point;
2827: break;
2828: }
2829: }
2830: }
2831: meetSize = newMeetSize;
2832: i = 1-i;
2833: }
2834: if (meetSize) break;
2835: }
2836: *numCoveredPoints = meetSize;
2837: *coveredPoints = meet[i];
2838: for (p = 0; p < numPoints; ++p) {
2839: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2840: }
2841: PetscFree(closures);
2842: DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2843: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2844: return(0);
2845: }
2847: /*@C
2848: DMPlexEqual - Determine if two DMs have the same topology
2850: Not Collective
2852: Input Parameters:
2853: + dmA - A DMPlex object
2854: - dmB - A DMPlex object
2856: Output Parameters:
2857: . equal - PETSC_TRUE if the topologies are identical
2859: Level: intermediate
2861: Notes:
2862: We are not solving graph isomorphism, so we do not permutation.
2864: .keywords: mesh
2865: .seealso: DMPlexGetCone()
2866: @*/
2867: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2868: {
2869: PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
2877: *equal = PETSC_FALSE;
2878: DMPlexGetDepth(dmA, &depth);
2879: DMPlexGetDepth(dmB, &depthB);
2880: if (depth != depthB) return(0);
2881: DMPlexGetChart(dmA, &pStart, &pEnd);
2882: DMPlexGetChart(dmB, &pStartB, &pEndB);
2883: if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2884: for (p = pStart; p < pEnd; ++p) {
2885: const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2886: PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s;
2888: DMPlexGetConeSize(dmA, p, &coneSize);
2889: DMPlexGetCone(dmA, p, &cone);
2890: DMPlexGetConeOrientation(dmA, p, &ornt);
2891: DMPlexGetConeSize(dmB, p, &coneSizeB);
2892: DMPlexGetCone(dmB, p, &coneB);
2893: DMPlexGetConeOrientation(dmB, p, &orntB);
2894: if (coneSize != coneSizeB) return(0);
2895: for (c = 0; c < coneSize; ++c) {
2896: if (cone[c] != coneB[c]) return(0);
2897: if (ornt[c] != orntB[c]) return(0);
2898: }
2899: DMPlexGetSupportSize(dmA, p, &supportSize);
2900: DMPlexGetSupport(dmA, p, &support);
2901: DMPlexGetSupportSize(dmB, p, &supportSizeB);
2902: DMPlexGetSupport(dmB, p, &supportB);
2903: if (supportSize != supportSizeB) return(0);
2904: for (s = 0; s < supportSize; ++s) {
2905: if (support[s] != supportB[s]) return(0);
2906: }
2907: }
2908: *equal = PETSC_TRUE;
2909: return(0);
2910: }
2912: /*@C
2913: DMPlexGetNumFaceVertices - Returns the number of vertices on a face
2915: Not Collective
2917: Input Parameters:
2918: + dm - The DMPlex
2919: . cellDim - The cell dimension
2920: - numCorners - The number of vertices on a cell
2922: Output Parameters:
2923: . numFaceVertices - The number of vertices on a face
2925: Level: developer
2927: Notes:
2928: Of course this can only work for a restricted set of symmetric shapes
2930: .seealso: DMPlexGetCone()
2931: @*/
2932: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2933: {
2934: MPI_Comm comm;
2938: PetscObjectGetComm((PetscObject)dm,&comm);
2940: switch (cellDim) {
2941: case 0:
2942: *numFaceVertices = 0;
2943: break;
2944: case 1:
2945: *numFaceVertices = 1;
2946: break;
2947: case 2:
2948: switch (numCorners) {
2949: case 3: /* triangle */
2950: *numFaceVertices = 2; /* Edge has 2 vertices */
2951: break;
2952: case 4: /* quadrilateral */
2953: *numFaceVertices = 2; /* Edge has 2 vertices */
2954: break;
2955: case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2956: *numFaceVertices = 3; /* Edge has 3 vertices */
2957: break;
2958: case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2959: *numFaceVertices = 3; /* Edge has 3 vertices */
2960: break;
2961: default:
2962: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2963: }
2964: break;
2965: case 3:
2966: switch (numCorners) {
2967: case 4: /* tetradehdron */
2968: *numFaceVertices = 3; /* Face has 3 vertices */
2969: break;
2970: case 6: /* tet cohesive cells */
2971: *numFaceVertices = 4; /* Face has 4 vertices */
2972: break;
2973: case 8: /* hexahedron */
2974: *numFaceVertices = 4; /* Face has 4 vertices */
2975: break;
2976: case 9: /* tet cohesive Lagrange cells */
2977: *numFaceVertices = 6; /* Face has 6 vertices */
2978: break;
2979: case 10: /* quadratic tetrahedron */
2980: *numFaceVertices = 6; /* Face has 6 vertices */
2981: break;
2982: case 12: /* hex cohesive Lagrange cells */
2983: *numFaceVertices = 6; /* Face has 6 vertices */
2984: break;
2985: case 18: /* quadratic tet cohesive Lagrange cells */
2986: *numFaceVertices = 6; /* Face has 6 vertices */
2987: break;
2988: case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2989: *numFaceVertices = 9; /* Face has 9 vertices */
2990: break;
2991: default:
2992: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2993: }
2994: break;
2995: default:
2996: SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
2997: }
2998: return(0);
2999: }
3001: /*@
3002: DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
3004: Not Collective
3006: Input Parameter:
3007: . dm - The DMPlex object
3009: Output Parameter:
3010: . depthLabel - The DMLabel recording point depth
3012: Level: developer
3014: .keywords: mesh, points
3015: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3016: @*/
3017: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3018: {
3024: if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3025: *depthLabel = dm->depthLabel;
3026: return(0);
3027: }
3029: /*@
3030: DMPlexGetDepth - Get the depth of the DAG representing this mesh
3032: Not Collective
3034: Input Parameter:
3035: . dm - The DMPlex object
3037: Output Parameter:
3038: . depth - The number of strata (breadth first levels) in the DAG
3040: Level: developer
3042: .keywords: mesh, points
3043: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3044: @*/
3045: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3046: {
3047: DMLabel label;
3048: PetscInt d = 0;
3054: DMPlexGetDepthLabel(dm, &label);
3055: if (label) {DMLabelGetNumValues(label, &d);}
3056: *depth = d-1;
3057: return(0);
3058: }
3060: /*@
3061: DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
3063: Not Collective
3065: Input Parameters:
3066: + dm - The DMPlex object
3067: - stratumValue - The requested depth
3069: Output Parameters:
3070: + start - The first point at this depth
3071: - end - One beyond the last point at this depth
3073: Level: developer
3075: .keywords: mesh, points
3076: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3077: @*/
3078: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3079: {
3080: DMLabel label;
3081: PetscInt pStart, pEnd;
3088: DMPlexGetChart(dm, &pStart, &pEnd);
3089: if (pStart == pEnd) return(0);
3090: if (stratumValue < 0) {
3091: if (start) *start = pStart;
3092: if (end) *end = pEnd;
3093: return(0);
3094: }
3095: DMPlexGetDepthLabel(dm, &label);
3096: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3097: DMLabelGetStratumBounds(label, stratumValue, start, end);
3098: return(0);
3099: }
3101: /*@
3102: DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3104: Not Collective
3106: Input Parameters:
3107: + dm - The DMPlex object
3108: - stratumValue - The requested height
3110: Output Parameters:
3111: + start - The first point at this height
3112: - end - One beyond the last point at this height
3114: Level: developer
3116: .keywords: mesh, points
3117: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3118: @*/
3119: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3120: {
3121: DMLabel label;
3122: PetscInt depth, pStart, pEnd;
3129: DMPlexGetChart(dm, &pStart, &pEnd);
3130: if (pStart == pEnd) return(0);
3131: if (stratumValue < 0) {
3132: if (start) *start = pStart;
3133: if (end) *end = pEnd;
3134: return(0);
3135: }
3136: DMPlexGetDepthLabel(dm, &label);
3137: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3138: DMLabelGetNumValues(label, &depth);
3139: DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3140: return(0);
3141: }
3143: /* Set the number of dof on each point and separate by fields */
3144: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3145: {
3146: PetscInt *pMax;
3147: PetscInt depth, cellHeight, pStart = 0, pEnd = 0;
3148: PetscInt Nf, p, d, dep, f;
3149: PetscBool *isFE;
3153: PetscMalloc1(numFields, &isFE);
3154: DMGetNumFields(dm, &Nf);
3155: for (f = 0; f < numFields; ++f) {
3156: PetscObject obj;
3157: PetscClassId id;
3159: isFE[f] = PETSC_FALSE;
3160: if (f >= Nf) continue;
3161: DMGetField(dm, f, &obj);
3162: PetscObjectGetClassId(obj, &id);
3163: if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;}
3164: else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3165: }
3166: PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
3167: if (numFields > 0) {
3168: PetscSectionSetNumFields(*section, numFields);
3169: if (numComp) {
3170: for (f = 0; f < numFields; ++f) {
3171: PetscSectionSetFieldComponents(*section, f, numComp[f]);
3172: if (isFE[f]) {
3173: PetscFE fe;
3174: PetscDualSpace dspace;
3175: const PetscInt ***perms;
3176: const PetscScalar ***flips;
3177: const PetscInt *numDof;
3179: DMGetField(dm,f,(PetscObject *) &fe);
3180: PetscFEGetDualSpace(fe,&dspace);
3181: PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3182: PetscDualSpaceGetNumDof(dspace,&numDof);
3183: if (perms || flips) {
3184: DM K;
3185: DMLabel depthLabel;
3186: PetscInt depth, h;
3187: PetscSectionSym sym;
3189: PetscDualSpaceGetDM(dspace,&K);
3190: DMPlexGetDepthLabel(dm,&depthLabel);
3191: DMPlexGetDepth(dm,&depth);
3192: PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
3193: for (h = 0; h <= depth; h++) {
3194: PetscDualSpace hspace;
3195: PetscInt kStart, kEnd;
3196: PetscInt kConeSize;
3197: const PetscInt **perms0 = NULL;
3198: const PetscScalar **flips0 = NULL;
3200: PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3201: DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3202: if (!hspace) continue;
3203: PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3204: if (perms) perms0 = perms[0];
3205: if (flips) flips0 = flips[0];
3206: if (!(perms0 || flips0)) continue;
3207: DMPlexGetConeSize(K,kStart,&kConeSize);
3208: PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3209: }
3210: PetscSectionSetFieldSym(*section,f,sym);
3211: PetscSectionSymDestroy(&sym);
3212: }
3213: }
3214: }
3215: }
3216: }
3217: DMPlexGetChart(dm, &pStart, &pEnd);
3218: PetscSectionSetChart(*section, pStart, pEnd);
3219: DMPlexGetDepth(dm, &depth);
3220: PetscMalloc1(depth+1,&pMax);
3221: DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3222: DMPlexGetVTKCellHeight(dm, &cellHeight);
3223: for (dep = 0; dep <= depth - cellHeight; ++dep) {
3224: d = dim == depth ? dep : (!dep ? 0 : dim);
3225: DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3226: pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3227: for (p = pStart; p < pEnd; ++p) {
3228: PetscInt tot = 0;
3230: for (f = 0; f < numFields; ++f) {
3231: if (isFE[f] && p >= pMax[dep]) continue;
3232: PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3233: tot += numDof[f*(dim+1)+d];
3234: }
3235: PetscSectionSetDof(*section, p, tot);
3236: }
3237: }
3238: PetscFree(pMax);
3239: PetscFree(isFE);
3240: return(0);
3241: }
3243: /* Set the number of dof on each point and separate by fields
3244: If bcComps is NULL or the IS is NULL, constrain every dof on the point
3245: */
3246: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3247: {
3248: PetscInt numFields;
3249: PetscInt bc;
3250: PetscSection aSec;
3254: PetscSectionGetNumFields(section, &numFields);
3255: for (bc = 0; bc < numBC; ++bc) {
3256: PetscInt field = 0;
3257: const PetscInt *comp;
3258: const PetscInt *idx;
3259: PetscInt Nc = -1, n, i;
3261: if (numFields) field = bcField[bc];
3262: if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3263: if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3264: ISGetLocalSize(bcPoints[bc], &n);
3265: ISGetIndices(bcPoints[bc], &idx);
3266: for (i = 0; i < n; ++i) {
3267: const PetscInt p = idx[i];
3268: PetscInt numConst;
3270: if (numFields) {
3271: PetscSectionGetFieldDof(section, p, field, &numConst);
3272: } else {
3273: PetscSectionGetDof(section, p, &numConst);
3274: }
3275: /* If Nc < 0, constrain every dof on the point */
3276: if (Nc > 0) numConst = PetscMin(numConst, Nc);
3277: if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3278: PetscSectionAddConstraintDof(section, p, numConst);
3279: }
3280: ISRestoreIndices(bcPoints[bc], &idx);
3281: if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3282: }
3283: DMPlexGetAnchors(dm, &aSec, NULL);
3284: if (aSec) {
3285: PetscInt aStart, aEnd, a;
3287: PetscSectionGetChart(aSec, &aStart, &aEnd);
3288: for (a = aStart; a < aEnd; a++) {
3289: PetscInt dof, f;
3291: PetscSectionGetDof(aSec, a, &dof);
3292: if (dof) {
3293: /* if there are point-to-point constraints, then all dofs are constrained */
3294: PetscSectionGetDof(section, a, &dof);
3295: PetscSectionSetConstraintDof(section, a, dof);
3296: for (f = 0; f < numFields; f++) {
3297: PetscSectionGetFieldDof(section, a, f, &dof);
3298: PetscSectionSetFieldConstraintDof(section, a, f, dof);
3299: }
3300: }
3301: }
3302: }
3303: return(0);
3304: }
3306: /* Set the constrained field indices on each point
3307: If bcComps is NULL or the IS is NULL, constrain every dof on the point
3308: */
3309: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3310: {
3311: PetscSection aSec;
3312: PetscInt *indices;
3313: PetscInt numFields, cdof, maxDof = 0, pStart, pEnd, p, bc, f, d;
3317: PetscSectionGetNumFields(section, &numFields);
3318: if (!numFields) return(0);
3319: /* Initialize all field indices to -1 */
3320: PetscSectionGetChart(section, &pStart, &pEnd);
3321: for (p = pStart; p < pEnd; ++p) {PetscSectionGetConstraintDof(section, p, &cdof); maxDof = PetscMax(maxDof, cdof);}
3322: PetscMalloc1(maxDof, &indices);
3323: for (d = 0; d < maxDof; ++d) indices[d] = -1;
3324: for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3325: /* Handle BC constraints */
3326: for (bc = 0; bc < numBC; ++bc) {
3327: const PetscInt field = bcField[bc];
3328: const PetscInt *comp, *idx;
3329: PetscInt Nc = -1, n, i;
3331: if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3332: if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3333: ISGetLocalSize(bcPoints[bc], &n);
3334: ISGetIndices(bcPoints[bc], &idx);
3335: for (i = 0; i < n; ++i) {
3336: const PetscInt p = idx[i];
3337: const PetscInt *find;
3338: PetscInt fdof, fcdof, c;
3340: PetscSectionGetFieldDof(section, p, field, &fdof);
3341: if (!fdof) continue;
3342: if (Nc < 0) {
3343: for (d = 0; d < fdof; ++d) indices[d] = d;
3344: fcdof = fdof;
3345: } else {
3346: PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3347: PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3348: for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3349: for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
3350: PetscSortRemoveDupsInt(&d, indices);
3351: for (c = d; c < fcdof; ++c) indices[c] = -1;
3352: fcdof = d;
3353: }
3354: PetscSectionSetFieldConstraintDof(section, p, field, fcdof);
3355: PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3356: }
3357: if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3358: ISRestoreIndices(bcPoints[bc], &idx);
3359: }
3360: /* Handle anchors */
3361: DMPlexGetAnchors(dm, &aSec, NULL);
3362: if (aSec) {
3363: PetscInt aStart, aEnd, a;
3365: for (d = 0; d < maxDof; ++d) indices[d] = d;
3366: PetscSectionGetChart(aSec, &aStart, &aEnd);
3367: for (a = aStart; a < aEnd; a++) {
3368: PetscInt dof, f;
3370: PetscSectionGetDof(aSec, a, &dof);
3371: if (dof) {
3372: /* if there are point-to-point constraints, then all dofs are constrained */
3373: for (f = 0; f < numFields; f++) {
3374: PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3375: }
3376: }
3377: }
3378: }
3379: PetscFree(indices);
3380: return(0);
3381: }
3383: /* Set the constrained indices on each point */
3384: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3385: {
3386: PetscInt *indices;
3387: PetscInt numFields, maxDof, pStart, pEnd, p, f, d;
3391: PetscSectionGetNumFields(section, &numFields);
3392: PetscSectionGetMaxDof(section, &maxDof);
3393: PetscSectionGetChart(section, &pStart, &pEnd);
3394: PetscMalloc1(maxDof, &indices);
3395: for (d = 0; d < maxDof; ++d) indices[d] = -1;
3396: for (p = pStart; p < pEnd; ++p) {
3397: PetscInt cdof, d;
3399: PetscSectionGetConstraintDof(section, p, &cdof);
3400: if (cdof) {
3401: if (numFields) {
3402: PetscInt numConst = 0, foff = 0;
3404: for (f = 0; f < numFields; ++f) {
3405: const PetscInt *find;
3406: PetscInt fcdof, fdof;
3408: PetscSectionGetFieldDof(section, p, f, &fdof);
3409: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3410: /* Change constraint numbering from field component to local dof number */
3411: PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3412: for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3413: numConst += fcdof;
3414: foff += fdof;
3415: }
3416: if (cdof != numConst) {PetscSectionSetConstraintDof(section, p, numConst);}
3417: } else {
3418: for (d = 0; d < cdof; ++d) indices[d] = d;
3419: }
3420: PetscSectionSetConstraintIndices(section, p, indices);
3421: }
3422: }
3423: PetscFree(indices);
3424: return(0);
3425: }
3427: /*@C
3428: DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
3430: Not Collective
3432: Input Parameters:
3433: + dm - The DMPlex object
3434: . dim - The spatial dimension of the problem
3435: . numFields - The number of fields in the problem
3436: . numComp - An array of size numFields that holds the number of components for each field
3437: . numDof - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3438: . numBC - The number of boundary conditions
3439: . bcField - An array of size numBC giving the field number for each boundry condition
3440: . bcComps - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3441: . bcPoints - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3442: - perm - Optional permutation of the chart, or NULL
3444: Output Parameter:
3445: . section - The PetscSection object
3447: Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on points of dimension d. For instance, numDof[1] is the
3448: number of dof for field 0 on each edge.
3450: The chart permutation is the same one set using PetscSectionSetPermutation()
3452: Level: developer
3454: Fortran Notes:
3455: A Fortran 90 version is available as DMPlexCreateSectionF90()
3457: .keywords: mesh, elements
3458: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3459: @*/
3460: PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], IS perm, PetscSection *section)
3461: {
3462: PetscSection aSec;
3466: DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3467: DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3468: if (perm) {PetscSectionSetPermutation(*section, perm);}
3469: PetscSectionSetUp(*section);
3470: DMPlexGetAnchors(dm,&aSec,NULL);
3471: if (numBC || aSec) {
3472: DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3473: DMPlexCreateSectionBCIndices(dm, *section);
3474: }
3475: PetscSectionViewFromOptions(*section,NULL,"-section_view");
3476: return(0);
3477: }
3479: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3480: {
3481: PetscSection section, s;
3482: Mat m;
3483: PetscInt maxHeight;
3487: DMClone(dm, cdm);
3488: DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3489: DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3490: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
3491: DMSetDefaultSection(*cdm, section);
3492: PetscSectionDestroy(§ion);
3493: PetscSectionCreate(PETSC_COMM_SELF, &s);
3494: MatCreate(PETSC_COMM_SELF, &m);
3495: DMSetDefaultConstraints(*cdm, s, m);
3496: PetscSectionDestroy(&s);
3497: MatDestroy(&m);
3498: return(0);
3499: }
3501: /*@C
3502: DMPlexGetConeSection - Return a section which describes the layout of cone data
3504: Not Collective
3506: Input Parameters:
3507: . dm - The DMPlex object
3509: Output Parameter:
3510: . section - The PetscSection object
3512: Level: developer
3514: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3515: @*/
3516: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3517: {
3518: DM_Plex *mesh = (DM_Plex*) dm->data;
3522: if (section) *section = mesh->coneSection;
3523: return(0);
3524: }
3526: /*@C
3527: DMPlexGetSupportSection - Return a section which describes the layout of support data
3529: Not Collective
3531: Input Parameters:
3532: . dm - The DMPlex object
3534: Output Parameter:
3535: . section - The PetscSection object
3537: Level: developer
3539: .seealso: DMPlexGetConeSection()
3540: @*/
3541: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3542: {
3543: DM_Plex *mesh = (DM_Plex*) dm->data;
3547: if (section) *section = mesh->supportSection;
3548: return(0);
3549: }
3551: /*@C
3552: DMPlexGetCones - Return cone data
3554: Not Collective
3556: Input Parameters:
3557: . dm - The DMPlex object
3559: Output Parameter:
3560: . cones - The cone for each point
3562: Level: developer
3564: .seealso: DMPlexGetConeSection()
3565: @*/
3566: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3567: {
3568: DM_Plex *mesh = (DM_Plex*) dm->data;
3572: if (cones) *cones = mesh->cones;
3573: return(0);
3574: }
3576: /*@C
3577: DMPlexGetConeOrientations - Return cone orientation data
3579: Not Collective
3581: Input Parameters:
3582: . dm - The DMPlex object
3584: Output Parameter:
3585: . coneOrientations - The cone orientation for each point
3587: Level: developer
3589: .seealso: DMPlexGetConeSection()
3590: @*/
3591: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3592: {
3593: DM_Plex *mesh = (DM_Plex*) dm->data;
3597: if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3598: return(0);
3599: }
3601: /******************************** FEM Support **********************************/
3603: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3604: {
3605: DMLabel label;
3606: PetscInt *perm;
3607: PetscInt dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3611: if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3612: DMGetDimension(dm, &dim);
3613: DMPlexGetDepthLabel(dm, &label);
3614: DMLabelGetValue(label, point, &depth);
3615: if (depth == 1) {eStart = point;}
3616: else if (depth == dim) {
3617: const PetscInt *cone;
3619: DMPlexGetCone(dm, point, &cone);
3620: eStart = cone[0];
3621: } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering", point, depth);
3622: if (!section) {DMGetDefaultSection(dm, §ion);}
3623: PetscSectionGetNumFields(section, &Nf);
3624: if (dim <= 1) return(0);
3625: for (f = 0; f < Nf; ++f) {
3626: /* An order k SEM disc has k-1 dofs on an edge */
3627: PetscSectionGetFieldDof(section, eStart, f, &k);
3628: PetscSectionGetFieldComponents(section, f, &Nc);
3629: k = k/Nc + 1;
3630: size += PetscPowInt(k+1, dim)*Nc;
3631: }
3632: PetscMalloc1(size, &perm);
3633: for (f = 0; f < Nf; ++f) {
3634: switch (dim) {
3635: case 2:
3636: /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3637: PetscSectionGetFieldDof(section, eStart, f, &k);
3638: PetscSectionGetFieldComponents(section, f, &Nc);
3639: k = k/Nc + 1;
3640: /* The SEM order is
3642: v_lb, {e_b}, v_rb,
3643: e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3644: v_lt, reverse {e_t}, v_rt
3645: */
3646: {
3647: const PetscInt of = 0;
3648: const PetscInt oeb = of + PetscSqr(k-1);
3649: const PetscInt oer = oeb + (k-1);
3650: const PetscInt oet = oer + (k-1);
3651: const PetscInt oel = oet + (k-1);
3652: const PetscInt ovlb = oel + (k-1);
3653: const PetscInt ovrb = ovlb + 1;
3654: const PetscInt ovrt = ovrb + 1;
3655: const PetscInt ovlt = ovrt + 1;
3656: PetscInt o;
3658: /* bottom */
3659: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3660: for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3661: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3662: /* middle */
3663: for (i = 0; i < k-1; ++i) {
3664: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3665: 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;
3666: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3667: }
3668: /* top */
3669: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3670: for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3671: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3672: foffset = offset;
3673: }
3674: break;
3675: case 3:
3676: /* The original hex closure is
3678: {c,
3679: f_b, f_t, f_f, f_b, f_r, f_l,
3680: e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb,
3681: v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3682: */
3683: PetscSectionGetFieldDof(section, eStart, f, &k);
3684: PetscSectionGetFieldComponents(section, f, &Nc);
3685: k = k/Nc + 1;
3686: /* The SEM order is
3687: Bottom Slice
3688: v_blf, {e^{(k-1)-n}_bf}, v_brf,
3689: e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3690: v_blb, {e_bb}, v_brb,
3692: Middle Slice (j)
3693: {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3694: f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3695: e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3697: Top Slice
3698: v_tlf, {e_tf}, v_trf,
3699: e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3700: v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3701: */
3702: {
3703: const PetscInt oc = 0;
3704: const PetscInt ofb = oc + PetscSqr(k-1)*(k-1);
3705: const PetscInt oft = ofb + PetscSqr(k-1);
3706: const PetscInt off = oft + PetscSqr(k-1);
3707: const PetscInt ofk = off + PetscSqr(k-1);
3708: const PetscInt ofr = ofk + PetscSqr(k-1);
3709: const PetscInt ofl = ofr + PetscSqr(k-1);
3710: const PetscInt oebl = ofl + PetscSqr(k-1);
3711: const PetscInt oebb = oebl + (k-1);
3712: const PetscInt oebr = oebb + (k-1);
3713: const PetscInt oebf = oebr + (k-1);
3714: const PetscInt oetf = oebf + (k-1);
3715: const PetscInt oetr = oetf + (k-1);
3716: const PetscInt oetb = oetr + (k-1);
3717: const PetscInt oetl = oetb + (k-1);
3718: const PetscInt oerf = oetl + (k-1);
3719: const PetscInt oelf = oerf + (k-1);
3720: const PetscInt oelb = oelf + (k-1);
3721: const PetscInt oerb = oelb + (k-1);
3722: const PetscInt ovblf = oerb + (k-1);
3723: const PetscInt ovblb = ovblf + 1;
3724: const PetscInt ovbrb = ovblb + 1;
3725: const PetscInt ovbrf = ovbrb + 1;
3726: const PetscInt ovtlf = ovbrf + 1;
3727: const PetscInt ovtrf = ovtlf + 1;
3728: const PetscInt ovtrb = ovtrf + 1;
3729: const PetscInt ovtlb = ovtrb + 1;
3730: PetscInt o, n;
3732: /* Bottom Slice */
3733: /* bottom */
3734: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3735: for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3736: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3737: /* middle */
3738: for (i = 0; i < k-1; ++i) {
3739: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3740: 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;}
3741: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3742: }
3743: /* top */
3744: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3745: for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3746: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
3748: /* Middle Slice */
3749: for (j = 0; j < k-1; ++j) {
3750: /* bottom */
3751: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3752: 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;
3753: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3754: /* middle */
3755: for (i = 0; i < k-1; ++i) {
3756: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3757: 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;
3758: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3759: }
3760: /* top */
3761: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3762: 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;
3763: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3764: }
3766: /* Top Slice */
3767: /* bottom */
3768: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3769: for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3770: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3771: /* middle */
3772: for (i = 0; i < k-1; ++i) {
3773: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3774: for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3775: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3776: }
3777: /* top */
3778: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3779: for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3780: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
3782: foffset = offset;
3783: }
3784: break;
3785: default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3786: }
3787: }
3788: if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3789: /* Check permutation */
3790: {
3791: PetscInt *check;
3793: PetscMalloc1(size, &check);
3794: 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]);}
3795: for (i = 0; i < size; ++i) check[perm[i]] = i;
3796: for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3797: PetscFree(check);
3798: }
3799: PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3800: return(0);
3801: }
3803: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3804: {
3805: PetscDS prob;
3806: PetscInt depth, Nf, h;
3807: DMLabel label;
3811: prob = dm->prob;
3812: Nf = prob->Nf;
3813: label = dm->depthLabel;
3814: *dspace = NULL;
3815: if (field < Nf) {
3816: PetscObject disc = prob->disc[field];
3818: if (disc->classid == PETSCFE_CLASSID) {
3819: PetscDualSpace dsp;
3821: PetscFEGetDualSpace((PetscFE)disc,&dsp);
3822: DMLabelGetNumValues(label,&depth);
3823: DMLabelGetValue(label,point,&h);
3824: h = depth - 1 - h;
3825: if (h) {
3826: PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3827: } else {
3828: *dspace = dsp;
3829: }
3830: }
3831: }
3832: return(0);
3833: }
3836: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3837: {
3838: PetscScalar *array, *vArray;
3839: const PetscInt *cone, *coneO;
3840: PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0;
3841: PetscErrorCode ierr;
3844: PetscSectionGetChart(section, &pStart, &pEnd);
3845: DMPlexGetConeSize(dm, point, &numPoints);
3846: DMPlexGetCone(dm, point, &cone);
3847: DMPlexGetConeOrientation(dm, point, &coneO);
3848: if (!values || !*values) {
3849: if ((point >= pStart) && (point < pEnd)) {
3850: PetscInt dof;
3852: PetscSectionGetDof(section, point, &dof);
3853: size += dof;
3854: }
3855: for (p = 0; p < numPoints; ++p) {
3856: const PetscInt cp = cone[p];
3857: PetscInt dof;
3859: if ((cp < pStart) || (cp >= pEnd)) continue;
3860: PetscSectionGetDof(section, cp, &dof);
3861: size += dof;
3862: }
3863: if (!values) {
3864: if (csize) *csize = size;
3865: return(0);
3866: }
3867: DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
3868: } else {
3869: array = *values;
3870: }
3871: size = 0;
3872: VecGetArray(v, &vArray);
3873: if ((point >= pStart) && (point < pEnd)) {
3874: PetscInt dof, off, d;
3875: PetscScalar *varr;
3877: PetscSectionGetDof(section, point, &dof);
3878: PetscSectionGetOffset(section, point, &off);
3879: varr = &vArray[off];
3880: for (d = 0; d < dof; ++d, ++offset) {
3881: array[offset] = varr[d];
3882: }
3883: size += dof;
3884: }
3885: for (p = 0; p < numPoints; ++p) {
3886: const PetscInt cp = cone[p];
3887: PetscInt o = coneO[p];
3888: PetscInt dof, off, d;
3889: PetscScalar *varr;
3891: if ((cp < pStart) || (cp >= pEnd)) continue;
3892: PetscSectionGetDof(section, cp, &dof);
3893: PetscSectionGetOffset(section, cp, &off);
3894: varr = &vArray[off];
3895: if (o >= 0) {
3896: for (d = 0; d < dof; ++d, ++offset) {
3897: array[offset] = varr[d];
3898: }
3899: } else {
3900: for (d = dof-1; d >= 0; --d, ++offset) {
3901: array[offset] = varr[d];
3902: }
3903: }
3904: size += dof;
3905: }
3906: VecRestoreArray(v, &vArray);
3907: if (!*values) {
3908: if (csize) *csize = size;
3909: *values = array;
3910: } else {
3911: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3912: *csize = size;
3913: }
3914: return(0);
3915: }
3917: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3918: {
3919: const PetscInt *cla;
3920: PetscInt np, *pts = NULL;
3924: PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3925: if (!*clPoints) {
3926: PetscInt pStart, pEnd, p, q;
3928: PetscSectionGetChart(section, &pStart, &pEnd);
3929: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3930: /* Compress out points not in the section */
3931: for (p = 0, q = 0; p < np; p++) {
3932: PetscInt r = pts[2*p];
3933: if ((r >= pStart) && (r < pEnd)) {
3934: pts[q*2] = r;
3935: pts[q*2+1] = pts[2*p+1];
3936: ++q;
3937: }
3938: }
3939: np = q;
3940: cla = NULL;
3941: } else {
3942: PetscInt dof, off;
3944: PetscSectionGetDof(*clSec, point, &dof);
3945: PetscSectionGetOffset(*clSec, point, &off);
3946: ISGetIndices(*clPoints, &cla);
3947: np = dof/2;
3948: pts = (PetscInt *) &cla[off];
3949: }
3950: *numPoints = np;
3951: *points = pts;
3952: *clp = cla;
3954: return(0);
3955: }
3957: static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3958: {
3962: if (!*clPoints) {
3963: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3964: } else {
3965: ISRestoreIndices(*clPoints, clp);
3966: }
3967: *numPoints = 0;
3968: *points = NULL;
3969: *clSec = NULL;
3970: *clPoints = NULL;
3971: *clp = NULL;
3972: return(0);
3973: }
3975: 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[])
3976: {
3977: PetscInt offset = 0, p;
3978: const PetscInt **perms = NULL;
3979: const PetscScalar **flips = NULL;
3980: PetscErrorCode ierr;
3983: *size = 0;
3984: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3985: for (p = 0; p < numPoints; p++) {
3986: const PetscInt point = points[2*p];
3987: const PetscInt *perm = perms ? perms[p] : NULL;
3988: const PetscScalar *flip = flips ? flips[p] : NULL;
3989: PetscInt dof, off, d;
3990: const PetscScalar *varr;
3992: PetscSectionGetDof(section, point, &dof);
3993: PetscSectionGetOffset(section, point, &off);
3994: varr = &vArray[off];
3995: if (clperm) {
3996: if (perm) {
3997: for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
3998: } else {
3999: for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d];
4000: }
4001: if (flip) {
4002: for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d];
4003: }
4004: } else {
4005: if (perm) {
4006: for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
4007: } else {
4008: for (d = 0; d < dof; d++) array[offset + d ] = varr[d];
4009: }
4010: if (flip) {
4011: for (d = 0; d < dof; d++) array[offset + d ] *= flip[d];
4012: }
4013: }
4014: offset += dof;
4015: }
4016: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4017: *size = offset;
4018: return(0);
4019: }
4021: 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[])
4022: {
4023: PetscInt offset = 0, f;
4024: PetscErrorCode ierr;
4027: *size = 0;
4028: for (f = 0; f < numFields; ++f) {
4029: PetscInt p;
4030: const PetscInt **perms = NULL;
4031: const PetscScalar **flips = NULL;
4033: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4034: for (p = 0; p < numPoints; p++) {
4035: const PetscInt point = points[2*p];
4036: PetscInt fdof, foff, b;
4037: const PetscScalar *varr;
4038: const PetscInt *perm = perms ? perms[p] : NULL;
4039: const PetscScalar *flip = flips ? flips[p] : NULL;
4041: PetscSectionGetFieldDof(section, point, f, &fdof);
4042: PetscSectionGetFieldOffset(section, point, f, &foff);
4043: varr = &vArray[foff];
4044: if (clperm) {
4045: if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}}
4046: else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}}
4047: if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}}
4048: } else {
4049: if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}}
4050: else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}}
4051: if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}}
4052: }
4053: offset += fdof;
4054: }
4055: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4056: }
4057: *size = offset;
4058: return(0);
4059: }
4061: /*@C
4062: DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4064: Not collective
4066: Input Parameters:
4067: + dm - The DM
4068: . section - The section describing the layout in v, or NULL to use the default section
4069: . v - The local vector
4070: . point - The point in the DM
4071: . csize - The size of the input values array, or NULL
4072: - values - An array to use for the values, or NULL to have it allocated automatically
4074: Output Parameters:
4075: + csize - The number of values in the closure
4076: - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4078: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4079: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4080: $ assembly function, and a user may already have allocated storage for this operation.
4081: $
4082: $ A typical use could be
4083: $
4084: $ values = NULL;
4085: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4086: $ for (cl = 0; cl < clSize; ++cl) {
4087: $ <Compute on closure>
4088: $ }
4089: $ DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4090: $
4091: $ or
4092: $
4093: $ PetscMalloc1(clMaxSize, &values);
4094: $ for (p = pStart; p < pEnd; ++p) {
4095: $ clSize = clMaxSize;
4096: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4097: $ for (cl = 0; cl < clSize; ++cl) {
4098: $ <Compute on closure>
4099: $ }
4100: $ }
4101: $ PetscFree(values);
4103: Fortran Notes:
4104: Since it returns an array, this routine is only available in Fortran 90, and you must
4105: include petsc.h90 in your code.
4107: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4109: Level: intermediate
4111: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4112: @*/
4113: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4114: {
4115: PetscSection clSection;
4116: IS clPoints;
4117: PetscScalar *array;
4118: const PetscScalar *vArray;
4119: PetscInt *points = NULL;
4120: const PetscInt *clp, *perm;
4121: PetscInt depth, numFields, numPoints, size;
4122: PetscErrorCode ierr;
4126: if (!section) {DMGetDefaultSection(dm, §ion);}
4129: DMPlexGetDepth(dm, &depth);
4130: PetscSectionGetNumFields(section, &numFields);
4131: if (depth == 1 && numFields < 2) {
4132: DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4133: return(0);
4134: }
4135: /* Get points */
4136: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4137: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4138: /* Get array */
4139: if (!values || !*values) {
4140: PetscInt asize = 0, dof, p;
4142: for (p = 0; p < numPoints*2; p += 2) {
4143: PetscSectionGetDof(section, points[p], &dof);
4144: asize += dof;
4145: }
4146: if (!values) {
4147: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4148: if (csize) *csize = asize;
4149: return(0);
4150: }
4151: DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4152: } else {
4153: array = *values;
4154: }
4155: VecGetArrayRead(v, &vArray);
4156: /* Get values */
4157: if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4158: else {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4159: /* Cleanup points */
4160: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4161: /* Cleanup array */
4162: VecRestoreArrayRead(v, &vArray);
4163: if (!*values) {
4164: if (csize) *csize = size;
4165: *values = array;
4166: } else {
4167: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4168: *csize = size;
4169: }
4170: return(0);
4171: }
4173: /*@C
4174: DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4176: Not collective
4178: Input Parameters:
4179: + dm - The DM
4180: . section - The section describing the layout in v, or NULL to use the default section
4181: . v - The local vector
4182: . point - The point in the DM
4183: . csize - The number of values in the closure, or NULL
4184: - values - The array of values, which is a borrowed array and should not be freed
4186: Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4188: Fortran Notes:
4189: Since it returns an array, this routine is only available in Fortran 90, and you must
4190: include petsc.h90 in your code.
4192: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4194: Level: intermediate
4196: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4197: @*/
4198: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4199: {
4200: PetscInt size = 0;
4204: /* Should work without recalculating size */
4205: DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4206: *values = NULL;
4207: return(0);
4208: }
4210: PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;}
4211: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;}
4213: 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[])
4214: {
4215: PetscInt cdof; /* The number of constraints on this point */
4216: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4217: PetscScalar *a;
4218: PetscInt off, cind = 0, k;
4219: PetscErrorCode ierr;
4222: PetscSectionGetConstraintDof(section, point, &cdof);
4223: PetscSectionGetOffset(section, point, &off);
4224: a = &array[off];
4225: if (!cdof || setBC) {
4226: if (clperm) {
4227: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4228: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}}
4229: } else {
4230: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4231: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}}
4232: }
4233: } else {
4234: PetscSectionGetConstraintIndices(section, point, &cdofs);
4235: if (clperm) {
4236: if (perm) {for (k = 0; k < dof; ++k) {
4237: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4238: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4239: }
4240: } else {
4241: for (k = 0; k < dof; ++k) {
4242: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4243: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4244: }
4245: }
4246: } else {
4247: if (perm) {
4248: for (k = 0; k < dof; ++k) {
4249: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4250: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4251: }
4252: } else {
4253: for (k = 0; k < dof; ++k) {
4254: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4255: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4256: }
4257: }
4258: }
4259: }
4260: return(0);
4261: }
4263: 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[])
4264: {
4265: PetscInt cdof; /* The number of constraints on this point */
4266: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4267: PetscScalar *a;
4268: PetscInt off, cind = 0, k;
4269: PetscErrorCode ierr;
4272: PetscSectionGetConstraintDof(section, point, &cdof);
4273: PetscSectionGetOffset(section, point, &off);
4274: a = &array[off];
4275: if (cdof) {
4276: PetscSectionGetConstraintIndices(section, point, &cdofs);
4277: if (clperm) {
4278: if (perm) {
4279: for (k = 0; k < dof; ++k) {
4280: if ((cind < cdof) && (k == cdofs[cind])) {
4281: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4282: cind++;
4283: }
4284: }
4285: } else {
4286: for (k = 0; k < dof; ++k) {
4287: if ((cind < cdof) && (k == cdofs[cind])) {
4288: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4289: cind++;
4290: }
4291: }
4292: }
4293: } else {
4294: if (perm) {
4295: for (k = 0; k < dof; ++k) {
4296: if ((cind < cdof) && (k == cdofs[cind])) {
4297: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4298: cind++;
4299: }
4300: }
4301: } else {
4302: for (k = 0; k < dof; ++k) {
4303: if ((cind < cdof) && (k == cdofs[cind])) {
4304: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4305: cind++;
4306: }
4307: }
4308: }
4309: }
4310: }
4311: return(0);
4312: }
4314: 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[])
4315: {
4316: PetscScalar *a;
4317: PetscInt fdof, foff, fcdof, foffset = *offset;
4318: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4319: PetscInt cind = 0, b;
4320: PetscErrorCode ierr;
4323: PetscSectionGetFieldDof(section, point, f, &fdof);
4324: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4325: PetscSectionGetFieldOffset(section, point, f, &foff);
4326: a = &array[foff];
4327: if (!fcdof || setBC) {
4328: if (clperm) {
4329: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4330: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}}
4331: } else {
4332: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4333: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}}
4334: }
4335: } else {
4336: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4337: if (clperm) {
4338: if (perm) {
4339: for (b = 0; b < fdof; b++) {
4340: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4341: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4342: }
4343: } else {
4344: for (b = 0; b < fdof; b++) {
4345: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4346: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4347: }
4348: }
4349: } else {
4350: if (perm) {
4351: for (b = 0; b < fdof; b++) {
4352: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4353: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4354: }
4355: } else {
4356: for (b = 0; b < fdof; b++) {
4357: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4358: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4359: }
4360: }
4361: }
4362: }
4363: *offset += fdof;
4364: return(0);
4365: }
4367: 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[])
4368: {
4369: PetscScalar *a;
4370: PetscInt fdof, foff, fcdof, foffset = *offset;
4371: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4372: PetscInt cind = 0, ncind = 0, b;
4373: PetscBool ncSet, fcSet;
4374: PetscErrorCode ierr;
4377: PetscSectionGetFieldDof(section, point, f, &fdof);
4378: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4379: PetscSectionGetFieldOffset(section, point, f, &foff);
4380: a = &array[foff];
4381: if (fcdof) {
4382: /* We just override fcdof and fcdofs with Ncc and comps */
4383: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4384: if (clperm) {
4385: if (perm) {
4386: if (comps) {
4387: for (b = 0; b < fdof; b++) {
4388: ncSet = fcSet = PETSC_FALSE;
4389: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4390: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4391: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4392: }
4393: } else {
4394: for (b = 0; b < fdof; b++) {
4395: if ((cind < fcdof) && (b == fcdofs[cind])) {
4396: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4397: ++cind;
4398: }
4399: }
4400: }
4401: } else {
4402: if (comps) {
4403: for (b = 0; b < fdof; b++) {
4404: ncSet = fcSet = PETSC_FALSE;
4405: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4406: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4407: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}
4408: }
4409: } else {
4410: for (b = 0; b < fdof; b++) {
4411: if ((cind < fcdof) && (b == fcdofs[cind])) {
4412: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4413: ++cind;
4414: }
4415: }
4416: }
4417: }
4418: } else {
4419: if (perm) {
4420: if (comps) {
4421: for (b = 0; b < fdof; b++) {
4422: ncSet = fcSet = PETSC_FALSE;
4423: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4424: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4425: if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4426: }
4427: } else {
4428: for (b = 0; b < fdof; b++) {
4429: if ((cind < fcdof) && (b == fcdofs[cind])) {
4430: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4431: ++cind;
4432: }
4433: }
4434: }
4435: } else {
4436: if (comps) {
4437: for (b = 0; b < fdof; b++) {
4438: ncSet = fcSet = PETSC_FALSE;
4439: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4440: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4441: if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}
4442: }
4443: } else {
4444: for (b = 0; b < fdof; b++) {
4445: if ((cind < fcdof) && (b == fcdofs[cind])) {
4446: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4447: ++cind;
4448: }
4449: }
4450: }
4451: }
4452: }
4453: }
4454: *offset += fdof;
4455: return(0);
4456: }
4458: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4459: {
4460: PetscScalar *array;
4461: const PetscInt *cone, *coneO;
4462: PetscInt pStart, pEnd, p, numPoints, off, dof;
4463: PetscErrorCode ierr;
4466: PetscSectionGetChart(section, &pStart, &pEnd);
4467: DMPlexGetConeSize(dm, point, &numPoints);
4468: DMPlexGetCone(dm, point, &cone);
4469: DMPlexGetConeOrientation(dm, point, &coneO);
4470: VecGetArray(v, &array);
4471: for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4472: const PetscInt cp = !p ? point : cone[p-1];
4473: const PetscInt o = !p ? 0 : coneO[p-1];
4475: if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4476: PetscSectionGetDof(section, cp, &dof);
4477: /* ADD_VALUES */
4478: {
4479: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4480: PetscScalar *a;
4481: PetscInt cdof, coff, cind = 0, k;
4483: PetscSectionGetConstraintDof(section, cp, &cdof);
4484: PetscSectionGetOffset(section, cp, &coff);
4485: a = &array[coff];
4486: if (!cdof) {
4487: if (o >= 0) {
4488: for (k = 0; k < dof; ++k) {
4489: a[k] += values[off+k];
4490: }
4491: } else {
4492: for (k = 0; k < dof; ++k) {
4493: a[k] += values[off+dof-k-1];
4494: }
4495: }
4496: } else {
4497: PetscSectionGetConstraintIndices(section, cp, &cdofs);
4498: if (o >= 0) {
4499: for (k = 0; k < dof; ++k) {
4500: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4501: a[k] += values[off+k];
4502: }
4503: } else {
4504: for (k = 0; k < dof; ++k) {
4505: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4506: a[k] += values[off+dof-k-1];
4507: }
4508: }
4509: }
4510: }
4511: }
4512: VecRestoreArray(v, &array);
4513: return(0);
4514: }
4516: /*@C
4517: DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4519: Not collective
4521: Input Parameters:
4522: + dm - The DM
4523: . section - The section describing the layout in v, or NULL to use the default section
4524: . v - The local vector
4525: . point - The point in the DM
4526: . values - The array of values
4527: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4528: where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
4530: Fortran Notes:
4531: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4533: Level: intermediate
4535: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4536: @*/
4537: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4538: {
4539: PetscSection clSection;
4540: IS clPoints;
4541: PetscScalar *array;
4542: PetscInt *points = NULL;
4543: const PetscInt *clp, *clperm;
4544: PetscInt depth, numFields, numPoints, p;
4545: PetscErrorCode ierr;
4549: if (!section) {DMGetDefaultSection(dm, §ion);}
4552: DMPlexGetDepth(dm, &depth);
4553: PetscSectionGetNumFields(section, &numFields);
4554: if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4555: DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4556: return(0);
4557: }
4558: /* Get points */
4559: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4560: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4561: /* Get array */
4562: VecGetArray(v, &array);
4563: /* Get values */
4564: if (numFields > 0) {
4565: PetscInt offset = 0, f;
4566: for (f = 0; f < numFields; ++f) {
4567: const PetscInt **perms = NULL;
4568: const PetscScalar **flips = NULL;
4570: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4571: switch (mode) {
4572: case INSERT_VALUES:
4573: for (p = 0; p < numPoints; p++) {
4574: const PetscInt point = points[2*p];
4575: const PetscInt *perm = perms ? perms[p] : NULL;
4576: const PetscScalar *flip = flips ? flips[p] : NULL;
4577: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4578: } break;
4579: case INSERT_ALL_VALUES:
4580: for (p = 0; p < numPoints; p++) {
4581: const PetscInt point = points[2*p];
4582: const PetscInt *perm = perms ? perms[p] : NULL;
4583: const PetscScalar *flip = flips ? flips[p] : NULL;
4584: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4585: } break;
4586: case INSERT_BC_VALUES:
4587: for (p = 0; p < numPoints; p++) {
4588: const PetscInt point = points[2*p];
4589: const PetscInt *perm = perms ? perms[p] : NULL;
4590: const PetscScalar *flip = flips ? flips[p] : NULL;
4591: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4592: } break;
4593: case ADD_VALUES:
4594: for (p = 0; p < numPoints; p++) {
4595: const PetscInt point = points[2*p];
4596: const PetscInt *perm = perms ? perms[p] : NULL;
4597: const PetscScalar *flip = flips ? flips[p] : NULL;
4598: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4599: } break;
4600: case ADD_ALL_VALUES:
4601: for (p = 0; p < numPoints; p++) {
4602: const PetscInt point = points[2*p];
4603: const PetscInt *perm = perms ? perms[p] : NULL;
4604: const PetscScalar *flip = flips ? flips[p] : NULL;
4605: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4606: } break;
4607: case ADD_BC_VALUES:
4608: for (p = 0; p < numPoints; p++) {
4609: const PetscInt point = points[2*p];
4610: const PetscInt *perm = perms ? perms[p] : NULL;
4611: const PetscScalar *flip = flips ? flips[p] : NULL;
4612: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4613: } break;
4614: default:
4615: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4616: }
4617: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4618: }
4619: } else {
4620: PetscInt dof, off;
4621: const PetscInt **perms = NULL;
4622: const PetscScalar **flips = NULL;
4624: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4625: switch (mode) {
4626: case INSERT_VALUES:
4627: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4628: const PetscInt point = points[2*p];
4629: const PetscInt *perm = perms ? perms[p] : NULL;
4630: const PetscScalar *flip = flips ? flips[p] : NULL;
4631: PetscSectionGetDof(section, point, &dof);
4632: updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4633: } break;
4634: case INSERT_ALL_VALUES:
4635: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4636: const PetscInt point = points[2*p];
4637: const PetscInt *perm = perms ? perms[p] : NULL;
4638: const PetscScalar *flip = flips ? flips[p] : NULL;
4639: PetscSectionGetDof(section, point, &dof);
4640: updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array);
4641: } break;
4642: case INSERT_BC_VALUES:
4643: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4644: const PetscInt point = points[2*p];
4645: const PetscInt *perm = perms ? perms[p] : NULL;
4646: const PetscScalar *flip = flips ? flips[p] : NULL;
4647: PetscSectionGetDof(section, point, &dof);
4648: updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array);
4649: } break;
4650: case ADD_VALUES:
4651: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4652: const PetscInt point = points[2*p];
4653: const PetscInt *perm = perms ? perms[p] : NULL;
4654: const PetscScalar *flip = flips ? flips[p] : NULL;
4655: PetscSectionGetDof(section, point, &dof);
4656: updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array);
4657: } break;
4658: case ADD_ALL_VALUES:
4659: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4660: const PetscInt point = points[2*p];
4661: const PetscInt *perm = perms ? perms[p] : NULL;
4662: const PetscScalar *flip = flips ? flips[p] : NULL;
4663: PetscSectionGetDof(section, point, &dof);
4664: updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array);
4665: } break;
4666: case ADD_BC_VALUES:
4667: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4668: const PetscInt point = points[2*p];
4669: const PetscInt *perm = perms ? perms[p] : NULL;
4670: const PetscScalar *flip = flips ? flips[p] : NULL;
4671: PetscSectionGetDof(section, point, &dof);
4672: updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array);
4673: } break;
4674: default:
4675: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4676: }
4677: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4678: }
4679: /* Cleanup points */
4680: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4681: /* Cleanup array */
4682: VecRestoreArray(v, &array);
4683: return(0);
4684: }
4686: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4687: {
4688: PetscSection clSection;
4689: IS clPoints;
4690: PetscScalar *array;
4691: PetscInt *points = NULL;
4692: const PetscInt *clp, *clperm;
4693: PetscInt numFields, numPoints, p;
4694: PetscInt offset = 0, f;
4695: PetscErrorCode ierr;
4699: if (!section) {DMGetDefaultSection(dm, §ion);}
4702: PetscSectionGetNumFields(section, &numFields);
4703: /* Get points */
4704: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4705: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4706: /* Get array */
4707: VecGetArray(v, &array);
4708: /* Get values */
4709: for (f = 0; f < numFields; ++f) {
4710: const PetscInt **perms = NULL;
4711: const PetscScalar **flips = NULL;
4713: if (!fieldActive[f]) {
4714: for (p = 0; p < numPoints*2; p += 2) {
4715: PetscInt fdof;
4716: PetscSectionGetFieldDof(section, points[p], f, &fdof);
4717: offset += fdof;
4718: }
4719: continue;
4720: }
4721: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4722: switch (mode) {
4723: case INSERT_VALUES:
4724: for (p = 0; p < numPoints; p++) {
4725: const PetscInt point = points[2*p];
4726: const PetscInt *perm = perms ? perms[p] : NULL;
4727: const PetscScalar *flip = flips ? flips[p] : NULL;
4728: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4729: } break;
4730: case INSERT_ALL_VALUES:
4731: for (p = 0; p < numPoints; p++) {
4732: const PetscInt point = points[2*p];
4733: const PetscInt *perm = perms ? perms[p] : NULL;
4734: const PetscScalar *flip = flips ? flips[p] : NULL;
4735: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4736: } break;
4737: case INSERT_BC_VALUES:
4738: for (p = 0; p < numPoints; p++) {
4739: const PetscInt point = points[2*p];
4740: const PetscInt *perm = perms ? perms[p] : NULL;
4741: const PetscScalar *flip = flips ? flips[p] : NULL;
4742: updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4743: } break;
4744: case ADD_VALUES:
4745: for (p = 0; p < numPoints; p++) {
4746: const PetscInt point = points[2*p];
4747: const PetscInt *perm = perms ? perms[p] : NULL;
4748: const PetscScalar *flip = flips ? flips[p] : NULL;
4749: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4750: } break;
4751: case ADD_ALL_VALUES:
4752: for (p = 0; p < numPoints; p++) {
4753: const PetscInt point = points[2*p];
4754: const PetscInt *perm = perms ? perms[p] : NULL;
4755: const PetscScalar *flip = flips ? flips[p] : NULL;
4756: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4757: } break;
4758: default:
4759: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4760: }
4761: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4762: }
4763: /* Cleanup points */
4764: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4765: /* Cleanup array */
4766: VecRestoreArray(v, &array);
4767: return(0);
4768: }
4770: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4771: {
4772: PetscMPIInt rank;
4773: PetscInt i, j;
4777: MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4778: PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4779: for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4780: for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4781: numCIndices = numCIndices ? numCIndices : numRIndices;
4782: for (i = 0; i < numRIndices; i++) {
4783: PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4784: for (j = 0; j < numCIndices; j++) {
4785: #if defined(PETSC_USE_COMPLEX)
4786: PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4787: #else
4788: PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4789: #endif
4790: }
4791: PetscViewerASCIIPrintf(viewer, "\n");
4792: }
4793: return(0);
4794: }
4796: /* . off - The global offset of this point */
4797: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4798: {
4799: PetscInt dof; /* The number of unknowns on this point */
4800: PetscInt cdof; /* The number of constraints on this point */
4801: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4802: PetscInt cind = 0, k;
4803: PetscErrorCode ierr;
4806: PetscSectionGetDof(section, point, &dof);
4807: PetscSectionGetConstraintDof(section, point, &cdof);
4808: if (!cdof || setBC) {
4809: if (perm) {
4810: for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4811: } else {
4812: for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4813: }
4814: } else {
4815: PetscSectionGetConstraintIndices(section, point, &cdofs);
4816: if (perm) {
4817: for (k = 0; k < dof; ++k) {
4818: if ((cind < cdof) && (k == cdofs[cind])) {
4819: /* Insert check for returning constrained indices */
4820: indices[*loff+perm[k]] = -(off+k+1);
4821: ++cind;
4822: } else {
4823: indices[*loff+perm[k]] = off+k-cind;
4824: }
4825: }
4826: } else {
4827: for (k = 0; k < dof; ++k) {
4828: if ((cind < cdof) && (k == cdofs[cind])) {
4829: /* Insert check for returning constrained indices */
4830: indices[*loff+k] = -(off+k+1);
4831: ++cind;
4832: } else {
4833: indices[*loff+k] = off+k-cind;
4834: }
4835: }
4836: }
4837: }
4838: *loff += dof;
4839: return(0);
4840: }
4842: /* . off - The global offset of this point */
4843: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4844: {
4845: PetscInt numFields, foff, f;
4849: PetscSectionGetNumFields(section, &numFields);
4850: for (f = 0, foff = 0; f < numFields; ++f) {
4851: PetscInt fdof, cfdof;
4852: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4853: PetscInt cind = 0, b;
4854: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4856: PetscSectionGetFieldDof(section, point, f, &fdof);
4857: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4858: if (!cfdof || setBC) {
4859: if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4860: else {for (b = 0; b < fdof; b++) {indices[foffs[f]+ b ] = off+foff+b;}}
4861: } else {
4862: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4863: if (perm) {
4864: for (b = 0; b < fdof; b++) {
4865: if ((cind < cfdof) && (b == fcdofs[cind])) {
4866: indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4867: ++cind;
4868: } else {
4869: indices[foffs[f]+perm[b]] = off+foff+b-cind;
4870: }
4871: }
4872: } else {
4873: for (b = 0; b < fdof; b++) {
4874: if ((cind < cfdof) && (b == fcdofs[cind])) {
4875: indices[foffs[f]+b] = -(off+foff+b+1);
4876: ++cind;
4877: } else {
4878: indices[foffs[f]+b] = off+foff+b-cind;
4879: }
4880: }
4881: }
4882: }
4883: foff += (setBC ? fdof : (fdof - cfdof));
4884: foffs[f] += fdof;
4885: }
4886: return(0);
4887: }
4889: 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)
4890: {
4891: Mat cMat;
4892: PetscSection aSec, cSec;
4893: IS aIS;
4894: PetscInt aStart = -1, aEnd = -1;
4895: const PetscInt *anchors;
4896: PetscInt numFields, f, p, q, newP = 0;
4897: PetscInt newNumPoints = 0, newNumIndices = 0;
4898: PetscInt *newPoints, *indices, *newIndices;
4899: PetscInt maxAnchor, maxDof;
4900: PetscInt newOffsets[32];
4901: PetscInt *pointMatOffsets[32];
4902: PetscInt *newPointOffsets[32];
4903: PetscScalar *pointMat[32];
4904: PetscScalar *newValues=NULL,*tmpValues;
4905: PetscBool anyConstrained = PETSC_FALSE;
4906: PetscErrorCode ierr;
4911: PetscSectionGetNumFields(section, &numFields);
4913: DMPlexGetAnchors(dm,&aSec,&aIS);
4914: /* if there are point-to-point constraints */
4915: if (aSec) {
4916: PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4917: ISGetIndices(aIS,&anchors);
4918: PetscSectionGetChart(aSec,&aStart,&aEnd);
4919: /* figure out how many points are going to be in the new element matrix
4920: * (we allow double counting, because it's all just going to be summed
4921: * into the global matrix anyway) */
4922: for (p = 0; p < 2*numPoints; p+=2) {
4923: PetscInt b = points[p];
4924: PetscInt bDof = 0, bSecDof;
4926: PetscSectionGetDof(section,b,&bSecDof);
4927: if (!bSecDof) {
4928: continue;
4929: }
4930: if (b >= aStart && b < aEnd) {
4931: PetscSectionGetDof(aSec,b,&bDof);
4932: }
4933: if (bDof) {
4934: /* this point is constrained */
4935: /* it is going to be replaced by its anchors */
4936: PetscInt bOff, q;
4938: anyConstrained = PETSC_TRUE;
4939: newNumPoints += bDof;
4940: PetscSectionGetOffset(aSec,b,&bOff);
4941: for (q = 0; q < bDof; q++) {
4942: PetscInt a = anchors[bOff + q];
4943: PetscInt aDof;
4945: PetscSectionGetDof(section,a,&aDof);
4946: newNumIndices += aDof;
4947: for (f = 0; f < numFields; ++f) {
4948: PetscInt fDof;
4950: PetscSectionGetFieldDof(section, a, f, &fDof);
4951: newOffsets[f+1] += fDof;
4952: }
4953: }
4954: }
4955: else {
4956: /* this point is not constrained */
4957: newNumPoints++;
4958: newNumIndices += bSecDof;
4959: for (f = 0; f < numFields; ++f) {
4960: PetscInt fDof;
4962: PetscSectionGetFieldDof(section, b, f, &fDof);
4963: newOffsets[f+1] += fDof;
4964: }
4965: }
4966: }
4967: }
4968: if (!anyConstrained) {
4969: if (outNumPoints) *outNumPoints = 0;
4970: if (outNumIndices) *outNumIndices = 0;
4971: if (outPoints) *outPoints = NULL;
4972: if (outValues) *outValues = NULL;
4973: if (aSec) {ISRestoreIndices(aIS,&anchors);}
4974: return(0);
4975: }
4977: if (outNumPoints) *outNumPoints = newNumPoints;
4978: if (outNumIndices) *outNumIndices = newNumIndices;
4980: for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
4982: if (!outPoints && !outValues) {
4983: if (offsets) {
4984: for (f = 0; f <= numFields; f++) {
4985: offsets[f] = newOffsets[f];
4986: }
4987: }
4988: if (aSec) {ISRestoreIndices(aIS,&anchors);}
4989: return(0);
4990: }
4992: if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
4994: DMGetDefaultConstraints(dm, &cSec, &cMat);
4996: /* workspaces */
4997: if (numFields) {
4998: for (f = 0; f < numFields; f++) {
4999: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5000: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5001: }
5002: }
5003: else {
5004: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5005: DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5006: }
5008: /* get workspaces for the point-to-point matrices */
5009: if (numFields) {
5010: PetscInt totalOffset, totalMatOffset;
5012: for (p = 0; p < numPoints; p++) {
5013: PetscInt b = points[2*p];
5014: PetscInt bDof = 0, bSecDof;
5016: PetscSectionGetDof(section,b,&bSecDof);
5017: if (!bSecDof) {
5018: for (f = 0; f < numFields; f++) {
5019: newPointOffsets[f][p + 1] = 0;
5020: pointMatOffsets[f][p + 1] = 0;
5021: }
5022: continue;
5023: }
5024: if (b >= aStart && b < aEnd) {
5025: PetscSectionGetDof(aSec, b, &bDof);
5026: }
5027: if (bDof) {
5028: for (f = 0; f < numFields; f++) {
5029: PetscInt fDof, q, bOff, allFDof = 0;
5031: PetscSectionGetFieldDof(section, b, f, &fDof);
5032: PetscSectionGetOffset(aSec, b, &bOff);
5033: for (q = 0; q < bDof; q++) {
5034: PetscInt a = anchors[bOff + q];
5035: PetscInt aFDof;
5037: PetscSectionGetFieldDof(section, a, f, &aFDof);
5038: allFDof += aFDof;
5039: }
5040: newPointOffsets[f][p+1] = allFDof;
5041: pointMatOffsets[f][p+1] = fDof * allFDof;
5042: }
5043: }
5044: else {
5045: for (f = 0; f < numFields; f++) {
5046: PetscInt fDof;
5048: PetscSectionGetFieldDof(section, b, f, &fDof);
5049: newPointOffsets[f][p+1] = fDof;
5050: pointMatOffsets[f][p+1] = 0;
5051: }
5052: }
5053: }
5054: for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5055: newPointOffsets[f][0] = totalOffset;
5056: pointMatOffsets[f][0] = totalMatOffset;
5057: for (p = 0; p < numPoints; p++) {
5058: newPointOffsets[f][p+1] += newPointOffsets[f][p];
5059: pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5060: }
5061: totalOffset = newPointOffsets[f][numPoints];
5062: totalMatOffset = pointMatOffsets[f][numPoints];
5063: DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5064: }
5065: }
5066: else {
5067: for (p = 0; p < numPoints; p++) {
5068: PetscInt b = points[2*p];
5069: PetscInt bDof = 0, bSecDof;
5071: PetscSectionGetDof(section,b,&bSecDof);
5072: if (!bSecDof) {
5073: newPointOffsets[0][p + 1] = 0;
5074: pointMatOffsets[0][p + 1] = 0;
5075: continue;
5076: }
5077: if (b >= aStart && b < aEnd) {
5078: PetscSectionGetDof(aSec, b, &bDof);
5079: }
5080: if (bDof) {
5081: PetscInt bOff, q, allDof = 0;
5083: PetscSectionGetOffset(aSec, b, &bOff);
5084: for (q = 0; q < bDof; q++) {
5085: PetscInt a = anchors[bOff + q], aDof;
5087: PetscSectionGetDof(section, a, &aDof);
5088: allDof += aDof;
5089: }
5090: newPointOffsets[0][p+1] = allDof;
5091: pointMatOffsets[0][p+1] = bSecDof * allDof;
5092: }
5093: else {
5094: newPointOffsets[0][p+1] = bSecDof;
5095: pointMatOffsets[0][p+1] = 0;
5096: }
5097: }
5098: newPointOffsets[0][0] = 0;
5099: pointMatOffsets[0][0] = 0;
5100: for (p = 0; p < numPoints; p++) {
5101: newPointOffsets[0][p+1] += newPointOffsets[0][p];
5102: pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5103: }
5104: DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5105: }
5107: /* output arrays */
5108: DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5110: /* get the point-to-point matrices; construct newPoints */
5111: PetscSectionGetMaxDof(aSec, &maxAnchor);
5112: PetscSectionGetMaxDof(section, &maxDof);
5113: DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5114: DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5115: if (numFields) {
5116: for (p = 0, newP = 0; p < numPoints; p++) {
5117: PetscInt b = points[2*p];
5118: PetscInt o = points[2*p+1];
5119: PetscInt bDof = 0, bSecDof;
5121: PetscSectionGetDof(section, b, &bSecDof);
5122: if (!bSecDof) {
5123: continue;
5124: }
5125: if (b >= aStart && b < aEnd) {
5126: PetscSectionGetDof(aSec, b, &bDof);
5127: }
5128: if (bDof) {
5129: PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5131: fStart[0] = 0;
5132: fEnd[0] = 0;
5133: for (f = 0; f < numFields; f++) {
5134: PetscInt fDof;
5136: PetscSectionGetFieldDof(cSec, b, f, &fDof);
5137: fStart[f+1] = fStart[f] + fDof;
5138: fEnd[f+1] = fStart[f+1];
5139: }
5140: PetscSectionGetOffset(cSec, b, &bOff);
5141: DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);
5143: fAnchorStart[0] = 0;
5144: fAnchorEnd[0] = 0;
5145: for (f = 0; f < numFields; f++) {
5146: PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5148: fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5149: fAnchorEnd[f+1] = fAnchorStart[f + 1];
5150: }
5151: PetscSectionGetOffset(aSec, b, &bOff);
5152: for (q = 0; q < bDof; q++) {
5153: PetscInt a = anchors[bOff + q], aOff;
5155: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5156: newPoints[2*(newP + q)] = a;
5157: newPoints[2*(newP + q) + 1] = 0;
5158: PetscSectionGetOffset(section, a, &aOff);
5159: DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5160: }
5161: newP += bDof;
5163: if (outValues) {
5164: /* get the point-to-point submatrix */
5165: for (f = 0; f < numFields; f++) {
5166: MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5167: }
5168: }
5169: }
5170: else {
5171: newPoints[2 * newP] = b;
5172: newPoints[2 * newP + 1] = o;
5173: newP++;
5174: }
5175: }
5176: } else {
5177: for (p = 0; p < numPoints; p++) {
5178: PetscInt b = points[2*p];
5179: PetscInt o = points[2*p+1];
5180: PetscInt bDof = 0, bSecDof;
5182: PetscSectionGetDof(section, b, &bSecDof);
5183: if (!bSecDof) {
5184: continue;
5185: }
5186: if (b >= aStart && b < aEnd) {
5187: PetscSectionGetDof(aSec, b, &bDof);
5188: }
5189: if (bDof) {
5190: PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5192: PetscSectionGetOffset(cSec, b, &bOff);
5193: DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);
5195: PetscSectionGetOffset (aSec, b, &bOff);
5196: for (q = 0; q < bDof; q++) {
5197: PetscInt a = anchors[bOff + q], aOff;
5199: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5201: newPoints[2*(newP + q)] = a;
5202: newPoints[2*(newP + q) + 1] = 0;
5203: PetscSectionGetOffset(section, a, &aOff);
5204: DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5205: }
5206: newP += bDof;
5208: /* get the point-to-point submatrix */
5209: if (outValues) {
5210: MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5211: }
5212: }
5213: else {
5214: newPoints[2 * newP] = b;
5215: newPoints[2 * newP + 1] = o;
5216: newP++;
5217: }
5218: }
5219: }
5221: if (outValues) {
5222: DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5223: PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5224: /* multiply constraints on the right */
5225: if (numFields) {
5226: for (f = 0; f < numFields; f++) {
5227: PetscInt oldOff = offsets[f];
5229: for (p = 0; p < numPoints; p++) {
5230: PetscInt cStart = newPointOffsets[f][p];
5231: PetscInt b = points[2 * p];
5232: PetscInt c, r, k;
5233: PetscInt dof;
5235: PetscSectionGetFieldDof(section,b,f,&dof);
5236: if (!dof) {
5237: continue;
5238: }
5239: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5240: PetscInt nCols = newPointOffsets[f][p+1]-cStart;
5241: const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5243: for (r = 0; r < numIndices; r++) {
5244: for (c = 0; c < nCols; c++) {
5245: for (k = 0; k < dof; k++) {
5246: tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5247: }
5248: }
5249: }
5250: }
5251: else {
5252: /* copy this column as is */
5253: for (r = 0; r < numIndices; r++) {
5254: for (c = 0; c < dof; c++) {
5255: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5256: }
5257: }
5258: }
5259: oldOff += dof;
5260: }
5261: }
5262: }
5263: else {
5264: PetscInt oldOff = 0;
5265: for (p = 0; p < numPoints; p++) {
5266: PetscInt cStart = newPointOffsets[0][p];
5267: PetscInt b = points[2 * p];
5268: PetscInt c, r, k;
5269: PetscInt dof;
5271: PetscSectionGetDof(section,b,&dof);
5272: if (!dof) {
5273: continue;
5274: }
5275: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5276: PetscInt nCols = newPointOffsets[0][p+1]-cStart;
5277: const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5279: for (r = 0; r < numIndices; r++) {
5280: for (c = 0; c < nCols; c++) {
5281: for (k = 0; k < dof; k++) {
5282: tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5283: }
5284: }
5285: }
5286: }
5287: else {
5288: /* copy this column as is */
5289: for (r = 0; r < numIndices; r++) {
5290: for (c = 0; c < dof; c++) {
5291: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5292: }
5293: }
5294: }
5295: oldOff += dof;
5296: }
5297: }
5299: if (multiplyLeft) {
5300: DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5301: PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5302: /* multiply constraints transpose on the left */
5303: if (numFields) {
5304: for (f = 0; f < numFields; f++) {
5305: PetscInt oldOff = offsets[f];
5307: for (p = 0; p < numPoints; p++) {
5308: PetscInt rStart = newPointOffsets[f][p];
5309: PetscInt b = points[2 * p];
5310: PetscInt c, r, k;
5311: PetscInt dof;
5313: PetscSectionGetFieldDof(section,b,f,&dof);
5314: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5315: PetscInt nRows = newPointOffsets[f][p+1]-rStart;
5316: const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5318: for (r = 0; r < nRows; r++) {
5319: for (c = 0; c < newNumIndices; c++) {
5320: for (k = 0; k < dof; k++) {
5321: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5322: }
5323: }
5324: }
5325: }
5326: else {
5327: /* copy this row as is */
5328: for (r = 0; r < dof; r++) {
5329: for (c = 0; c < newNumIndices; c++) {
5330: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5331: }
5332: }
5333: }
5334: oldOff += dof;
5335: }
5336: }
5337: }
5338: else {
5339: PetscInt oldOff = 0;
5341: for (p = 0; p < numPoints; p++) {
5342: PetscInt rStart = newPointOffsets[0][p];
5343: PetscInt b = points[2 * p];
5344: PetscInt c, r, k;
5345: PetscInt dof;
5347: PetscSectionGetDof(section,b,&dof);
5348: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5349: PetscInt nRows = newPointOffsets[0][p+1]-rStart;
5350: const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5352: for (r = 0; r < nRows; r++) {
5353: for (c = 0; c < newNumIndices; c++) {
5354: for (k = 0; k < dof; k++) {
5355: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5356: }
5357: }
5358: }
5359: }
5360: else {
5361: /* copy this row as is */
5362: for (r = 0; r < dof; r++) {
5363: for (c = 0; c < newNumIndices; c++) {
5364: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5365: }
5366: }
5367: }
5368: oldOff += dof;
5369: }
5370: }
5372: DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5373: }
5374: else {
5375: newValues = tmpValues;
5376: }
5377: }
5379: /* clean up */
5380: DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5381: DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5383: if (numFields) {
5384: for (f = 0; f < numFields; f++) {
5385: DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5386: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5387: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5388: }
5389: }
5390: else {
5391: DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5392: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5393: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5394: }
5395: ISRestoreIndices(aIS,&anchors);
5397: /* output */
5398: if (outPoints) {
5399: *outPoints = newPoints;
5400: }
5401: else {
5402: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5403: }
5404: if (outValues) {
5405: *outValues = newValues;
5406: }
5407: for (f = 0; f <= numFields; f++) {
5408: offsets[f] = newOffsets[f];
5409: }
5410: return(0);
5411: }
5413: /*@C
5414: DMPlexGetClosureIndices - Get the global indices in a vector v for all points in the closure of the given point
5416: Not collective
5418: Input Parameters:
5419: + dm - The DM
5420: . section - The section describing the layout in v, or NULL to use the default section
5421: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5422: - point - The mesh point
5424: Output parameters:
5425: + numIndices - The number of indices
5426: . indices - The indices
5427: - outOffsets - Field offset if not NULL
5429: Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5431: Level: advanced
5433: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5434: @*/
5435: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5436: {
5437: PetscSection clSection;
5438: IS clPoints;
5439: const PetscInt *clp;
5440: const PetscInt **perms[32] = {NULL};
5441: PetscInt *points = NULL, *pointsNew;
5442: PetscInt numPoints, numPointsNew;
5443: PetscInt offsets[32];
5444: PetscInt Nf, Nind, NindNew, off, globalOff, f, p;
5445: PetscErrorCode ierr;
5453: PetscSectionGetNumFields(section, &Nf);
5454: if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5455: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5456: /* Get points in closure */
5457: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5458: /* Get number of indices and indices per field */
5459: for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5460: PetscInt dof, fdof;
5462: PetscSectionGetDof(section, points[p], &dof);
5463: for (f = 0; f < Nf; ++f) {
5464: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5465: offsets[f+1] += fdof;
5466: }
5467: Nind += dof;
5468: }
5469: for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5470: if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5471: if (!Nf) offsets[1] = Nind;
5472: /* Get dual space symmetries */
5473: for (f = 0; f < PetscMax(1,Nf); f++) {
5474: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5475: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5476: }
5477: /* Correct for hanging node constraints */
5478: {
5479: DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5480: if (numPointsNew) {
5481: for (f = 0; f < PetscMax(1,Nf); f++) {
5482: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5483: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5484: }
5485: for (f = 0; f < PetscMax(1,Nf); f++) {
5486: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5487: else {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5488: }
5489: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5490: numPoints = numPointsNew;
5491: Nind = NindNew;
5492: points = pointsNew;
5493: }
5494: }
5495: /* Calculate indices */
5496: DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5497: if (Nf) {
5498: if (outOffsets) {
5499: PetscInt f;
5501: for (f = 0; f <= Nf; f++) {
5502: outOffsets[f] = offsets[f];
5503: }
5504: }
5505: for (p = 0; p < numPoints; p++) {
5506: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5507: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5508: }
5509: } else {
5510: for (p = 0, off = 0; p < numPoints; p++) {
5511: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5513: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5514: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5515: }
5516: }
5517: /* Cleanup points */
5518: for (f = 0; f < PetscMax(1,Nf); f++) {
5519: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5520: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5521: }
5522: if (numPointsNew) {
5523: DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5524: } else {
5525: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5526: }
5527: if (numIndices) *numIndices = Nind;
5528: return(0);
5529: }
5531: /*@C
5532: DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5534: Not collective
5536: Input Parameters:
5537: + dm - The DM
5538: . section - The section describing the layout in v, or NULL to use the default section
5539: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5540: . point - The mesh point
5541: . numIndices - The number of indices
5542: . indices - The indices
5543: - outOffsets - Field offset if not NULL
5545: Level: advanced
5547: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5548: @*/
5549: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5550: {
5556: DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5557: return(0);
5558: }
5560: /*@C
5561: DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5563: Not collective
5565: Input Parameters:
5566: + dm - The DM
5567: . section - The section describing the layout in v, or NULL to use the default section
5568: . globalSection - The section describing the layout in v, or NULL to use the default global section
5569: . A - The matrix
5570: . point - The point in the DM
5571: . values - The array of values
5572: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5574: Fortran Notes:
5575: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5577: Level: intermediate
5579: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5580: @*/
5581: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5582: {
5583: DM_Plex *mesh = (DM_Plex*) dm->data;
5584: PetscSection clSection;
5585: IS clPoints;
5586: PetscInt *points = NULL, *newPoints;
5587: const PetscInt *clp;
5588: PetscInt *indices;
5589: PetscInt offsets[32];
5590: const PetscInt **perms[32] = {NULL};
5591: const PetscScalar **flips[32] = {NULL};
5592: PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5593: PetscScalar *valCopy = NULL;
5594: PetscScalar *newValues;
5595: PetscErrorCode ierr;
5599: if (!section) {DMGetDefaultSection(dm, §ion);}
5601: if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5604: PetscSectionGetNumFields(section, &numFields);
5605: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5606: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5607: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5608: for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5609: PetscInt fdof;
5611: PetscSectionGetDof(section, points[p], &dof);
5612: for (f = 0; f < numFields; ++f) {
5613: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5614: offsets[f+1] += fdof;
5615: }
5616: numIndices += dof;
5617: }
5618: for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5620: if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5621: /* Get symmetries */
5622: for (f = 0; f < PetscMax(1,numFields); f++) {
5623: if (numFields) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5624: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5625: if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5626: PetscInt foffset = offsets[f];
5628: for (p = 0; p < numPoints; p++) {
5629: PetscInt point = points[2*p], fdof;
5630: const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5632: if (!numFields) {
5633: PetscSectionGetDof(section,point,&fdof);
5634: } else {
5635: PetscSectionGetFieldDof(section,point,f,&fdof);
5636: }
5637: if (flip) {
5638: PetscInt i, j, k;
5640: if (!valCopy) {
5641: DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5642: for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5643: values = valCopy;
5644: }
5645: for (i = 0; i < fdof; i++) {
5646: PetscScalar fval = flip[i];
5648: for (k = 0; k < numIndices; k++) {
5649: valCopy[numIndices * (foffset + i) + k] *= fval;
5650: valCopy[numIndices * k + (foffset + i)] *= fval;
5651: }
5652: }
5653: }
5654: foffset += fdof;
5655: }
5656: }
5657: }
5658: DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5659: if (newNumPoints) {
5660: if (valCopy) {
5661: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5662: }
5663: for (f = 0; f < PetscMax(1,numFields); f++) {
5664: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5665: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5666: }
5667: for (f = 0; f < PetscMax(1,numFields); f++) {
5668: if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5669: else {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5670: }
5671: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5672: numPoints = newNumPoints;
5673: numIndices = newNumIndices;
5674: points = newPoints;
5675: values = newValues;
5676: }
5677: DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5678: if (numFields) {
5679: for (p = 0; p < numPoints; p++) {
5680: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5681: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5682: }
5683: } else {
5684: for (p = 0, off = 0; p < numPoints; p++) {
5685: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5686: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5687: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5688: }
5689: }
5690: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5691: MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5692: if (mesh->printFEM > 1) {
5693: PetscInt i;
5694: PetscPrintf(PETSC_COMM_SELF, " Indices:");
5695: for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5696: PetscPrintf(PETSC_COMM_SELF, "\n");
5697: }
5698: if (ierr) {
5699: PetscMPIInt rank;
5700: PetscErrorCode ierr2;
5702: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5703: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5704: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5705: ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5706:
5707: }
5708: for (f = 0; f < PetscMax(1,numFields); f++) {
5709: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5710: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5711: }
5712: if (newNumPoints) {
5713: DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5714: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5715: }
5716: else {
5717: if (valCopy) {
5718: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5719: }
5720: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5721: }
5722: DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5723: return(0);
5724: }
5726: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5727: {
5728: DM_Plex *mesh = (DM_Plex*) dmf->data;
5729: PetscInt *fpoints = NULL, *ftotpoints = NULL;
5730: PetscInt *cpoints = NULL;
5731: PetscInt *findices, *cindices;
5732: PetscInt foffsets[32], coffsets[32];
5733: CellRefiner cellRefiner;
5734: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5735: PetscErrorCode ierr;
5740: if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5742: if (!csection) {DMGetDefaultSection(dmc, &csection);}
5744: if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5746: if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5749: PetscSectionGetNumFields(fsection, &numFields);
5750: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5751: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5752: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5753: /* Column indices */
5754: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5755: maxFPoints = numCPoints;
5756: /* Compress out points not in the section */
5757: /* TODO: Squeeze out points with 0 dof as well */
5758: PetscSectionGetChart(csection, &pStart, &pEnd);
5759: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5760: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5761: cpoints[q*2] = cpoints[p];
5762: cpoints[q*2+1] = cpoints[p+1];
5763: ++q;
5764: }
5765: }
5766: numCPoints = q;
5767: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5768: PetscInt fdof;
5770: PetscSectionGetDof(csection, cpoints[p], &dof);
5771: if (!dof) continue;
5772: for (f = 0; f < numFields; ++f) {
5773: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5774: coffsets[f+1] += fdof;
5775: }
5776: numCIndices += dof;
5777: }
5778: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5779: /* Row indices */
5780: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5781: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5782: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5783: for (r = 0, q = 0; r < numSubcells; ++r) {
5784: /* TODO Map from coarse to fine cells */
5785: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5786: /* Compress out points not in the section */
5787: PetscSectionGetChart(fsection, &pStart, &pEnd);
5788: for (p = 0; p < numFPoints*2; p += 2) {
5789: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5790: PetscSectionGetDof(fsection, fpoints[p], &dof);
5791: if (!dof) continue;
5792: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5793: if (s < q) continue;
5794: ftotpoints[q*2] = fpoints[p];
5795: ftotpoints[q*2+1] = fpoints[p+1];
5796: ++q;
5797: }
5798: }
5799: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5800: }
5801: numFPoints = q;
5802: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5803: PetscInt fdof;
5805: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5806: if (!dof) continue;
5807: for (f = 0; f < numFields; ++f) {
5808: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5809: foffsets[f+1] += fdof;
5810: }
5811: numFIndices += dof;
5812: }
5813: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5815: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5816: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5817: DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5818: DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5819: if (numFields) {
5820: const PetscInt **permsF[32] = {NULL};
5821: const PetscInt **permsC[32] = {NULL};
5823: for (f = 0; f < numFields; f++) {
5824: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5825: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5826: }
5827: for (p = 0; p < numFPoints; p++) {
5828: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5829: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5830: }
5831: for (p = 0; p < numCPoints; p++) {
5832: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5833: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5834: }
5835: for (f = 0; f < numFields; f++) {
5836: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5837: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5838: }
5839: } else {
5840: const PetscInt **permsF = NULL;
5841: const PetscInt **permsC = NULL;
5843: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5844: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5845: for (p = 0, off = 0; p < numFPoints; p++) {
5846: const PetscInt *perm = permsF ? permsF[p] : NULL;
5848: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5849: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5850: }
5851: for (p = 0, off = 0; p < numCPoints; p++) {
5852: const PetscInt *perm = permsC ? permsC[p] : NULL;
5854: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5855: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5856: }
5857: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5858: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5859: }
5860: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5861: /* TODO: flips */
5862: MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5863: if (ierr) {
5864: PetscMPIInt rank;
5865: PetscErrorCode ierr2;
5867: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5868: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5869: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5870: ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
5871: ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
5872:
5873: }
5874: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
5875: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5876: DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5877: DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5878: return(0);
5879: }
5881: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5882: {
5883: PetscInt *fpoints = NULL, *ftotpoints = NULL;
5884: PetscInt *cpoints = NULL;
5885: PetscInt foffsets[32], coffsets[32];
5886: CellRefiner cellRefiner;
5887: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5893: if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5895: if (!csection) {DMGetDefaultSection(dmc, &csection);}
5897: if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5899: if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5901: PetscSectionGetNumFields(fsection, &numFields);
5902: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5903: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5904: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5905: /* Column indices */
5906: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5907: maxFPoints = numCPoints;
5908: /* Compress out points not in the section */
5909: /* TODO: Squeeze out points with 0 dof as well */
5910: PetscSectionGetChart(csection, &pStart, &pEnd);
5911: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5912: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5913: cpoints[q*2] = cpoints[p];
5914: cpoints[q*2+1] = cpoints[p+1];
5915: ++q;
5916: }
5917: }
5918: numCPoints = q;
5919: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5920: PetscInt fdof;
5922: PetscSectionGetDof(csection, cpoints[p], &dof);
5923: if (!dof) continue;
5924: for (f = 0; f < numFields; ++f) {
5925: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5926: coffsets[f+1] += fdof;
5927: }
5928: numCIndices += dof;
5929: }
5930: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5931: /* Row indices */
5932: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5933: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5934: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5935: for (r = 0, q = 0; r < numSubcells; ++r) {
5936: /* TODO Map from coarse to fine cells */
5937: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5938: /* Compress out points not in the section */
5939: PetscSectionGetChart(fsection, &pStart, &pEnd);
5940: for (p = 0; p < numFPoints*2; p += 2) {
5941: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5942: PetscSectionGetDof(fsection, fpoints[p], &dof);
5943: if (!dof) continue;
5944: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5945: if (s < q) continue;
5946: ftotpoints[q*2] = fpoints[p];
5947: ftotpoints[q*2+1] = fpoints[p+1];
5948: ++q;
5949: }
5950: }
5951: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5952: }
5953: numFPoints = q;
5954: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5955: PetscInt fdof;
5957: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5958: if (!dof) continue;
5959: for (f = 0; f < numFields; ++f) {
5960: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5961: foffsets[f+1] += fdof;
5962: }
5963: numFIndices += dof;
5964: }
5965: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5967: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5968: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5969: if (numFields) {
5970: const PetscInt **permsF[32] = {NULL};
5971: const PetscInt **permsC[32] = {NULL};
5973: for (f = 0; f < numFields; f++) {
5974: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5975: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5976: }
5977: for (p = 0; p < numFPoints; p++) {
5978: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5979: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5980: }
5981: for (p = 0; p < numCPoints; p++) {
5982: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5983: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5984: }
5985: for (f = 0; f < numFields; f++) {
5986: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5987: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5988: }
5989: } else {
5990: const PetscInt **permsF = NULL;
5991: const PetscInt **permsC = NULL;
5993: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5994: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5995: for (p = 0, off = 0; p < numFPoints; p++) {
5996: const PetscInt *perm = permsF ? permsF[p] : NULL;
5998: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5999: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6000: }
6001: for (p = 0, off = 0; p < numCPoints; p++) {
6002: const PetscInt *perm = permsC ? permsC[p] : NULL;
6004: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6005: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6006: }
6007: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6008: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6009: }
6010: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6011: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6012: return(0);
6013: }
6015: /*@
6016: DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6018: Input Parameter:
6019: . dm - The DMPlex object
6021: Output Parameters:
6022: + cMax - The first hybrid cell
6023: . fMax - The first hybrid face
6024: . eMax - The first hybrid edge
6025: - vMax - The first hybrid vertex
6027: Level: developer
6029: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6030: @*/
6031: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6032: {
6033: DM_Plex *mesh = (DM_Plex*) dm->data;
6034: PetscInt dim;
6039: DMGetDimension(dm, &dim);
6040: if (cMax) *cMax = mesh->hybridPointMax[dim];
6041: if (fMax) *fMax = mesh->hybridPointMax[dim-1];
6042: if (eMax) *eMax = mesh->hybridPointMax[1];
6043: if (vMax) *vMax = mesh->hybridPointMax[0];
6044: return(0);
6045: }
6047: /*@
6048: DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6050: Input Parameters:
6051: . dm - The DMPlex object
6052: . cMax - The first hybrid cell
6053: . fMax - The first hybrid face
6054: . eMax - The first hybrid edge
6055: - vMax - The first hybrid vertex
6057: Level: developer
6059: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6060: @*/
6061: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6062: {
6063: DM_Plex *mesh = (DM_Plex*) dm->data;
6064: PetscInt dim;
6069: DMGetDimension(dm, &dim);
6070: if (cMax >= 0) mesh->hybridPointMax[dim] = cMax;
6071: if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
6072: if (eMax >= 0) mesh->hybridPointMax[1] = eMax;
6073: if (vMax >= 0) mesh->hybridPointMax[0] = vMax;
6074: return(0);
6075: }
6077: /*@C
6078: DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6080: Input Parameter:
6081: . dm - The DMPlex object
6083: Output Parameter:
6084: . cellHeight - The height of a cell
6086: Level: developer
6088: .seealso DMPlexSetVTKCellHeight()
6089: @*/
6090: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6091: {
6092: DM_Plex *mesh = (DM_Plex*) dm->data;
6097: *cellHeight = mesh->vtkCellHeight;
6098: return(0);
6099: }
6101: /*@C
6102: DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6104: Input Parameters:
6105: + dm - The DMPlex object
6106: - cellHeight - The height of a cell
6108: Level: developer
6110: .seealso DMPlexGetVTKCellHeight()
6111: @*/
6112: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6113: {
6114: DM_Plex *mesh = (DM_Plex*) dm->data;
6118: mesh->vtkCellHeight = cellHeight;
6119: return(0);
6120: }
6122: /* We can easily have a form that takes an IS instead */
6123: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6124: {
6125: PetscSection section, globalSection;
6126: PetscInt *numbers, p;
6130: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
6131: PetscSectionSetChart(section, pStart, pEnd);
6132: for (p = pStart; p < pEnd; ++p) {
6133: PetscSectionSetDof(section, p, 1);
6134: }
6135: PetscSectionSetUp(section);
6136: PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6137: PetscMalloc1(pEnd - pStart, &numbers);
6138: for (p = pStart; p < pEnd; ++p) {
6139: PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6140: if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6141: else numbers[p-pStart] += shift;
6142: }
6143: ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6144: if (globalSize) {
6145: PetscLayout layout;
6146: PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6147: PetscLayoutGetSize(layout, globalSize);
6148: PetscLayoutDestroy(&layout);
6149: }
6150: PetscSectionDestroy(§ion);
6151: PetscSectionDestroy(&globalSection);
6152: return(0);
6153: }
6155: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6156: {
6157: PetscInt cellHeight, cStart, cEnd, cMax;
6161: DMPlexGetVTKCellHeight(dm, &cellHeight);
6162: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6163: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6164: if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6165: DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6166: return(0);
6167: }
6169: /*@C
6170: DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6172: Input Parameter:
6173: . dm - The DMPlex object
6175: Output Parameter:
6176: . globalCellNumbers - Global cell numbers for all cells on this process
6178: Level: developer
6180: .seealso DMPlexGetVertexNumbering()
6181: @*/
6182: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6183: {
6184: DM_Plex *mesh = (DM_Plex*) dm->data;
6189: if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6190: *globalCellNumbers = mesh->globalCellNumbers;
6191: return(0);
6192: }
6194: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6195: {
6196: PetscInt vStart, vEnd, vMax;
6201: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6202: DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6203: if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6204: DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6205: return(0);
6206: }
6208: /*@C
6209: DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process
6211: Input Parameter:
6212: . dm - The DMPlex object
6214: Output Parameter:
6215: . globalVertexNumbers - Global vertex numbers for all vertices on this process
6217: Level: developer
6219: .seealso DMPlexGetCellNumbering()
6220: @*/
6221: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6222: {
6223: DM_Plex *mesh = (DM_Plex*) dm->data;
6228: if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6229: *globalVertexNumbers = mesh->globalVertexNumbers;
6230: return(0);
6231: }
6233: /*@C
6234: DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6236: Input Parameter:
6237: . dm - The DMPlex object
6239: Output Parameter:
6240: . globalPointNumbers - Global numbers for all points on this process
6242: Level: developer
6244: .seealso DMPlexGetCellNumbering()
6245: @*/
6246: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6247: {
6248: IS nums[4];
6249: PetscInt depths[4];
6250: PetscInt depth, d, shift = 0;
6255: DMPlexGetDepth(dm, &depth);
6256: /* For unstratified meshes use dim instead of depth */
6257: if (depth < 0) {DMGetDimension(dm, &depth);}
6258: depths[0] = depth; depths[1] = 0;
6259: for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6260: for (d = 0; d <= depth; ++d) {
6261: PetscInt pStart, pEnd, gsize;
6263: DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6264: DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6265: shift += gsize;
6266: }
6267: ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6268: for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6269: return(0);
6270: }
6273: /*@
6274: DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6276: Input Parameter:
6277: . dm - The DMPlex object
6279: Output Parameter:
6280: . ranks - The rank field
6282: Options Database Keys:
6283: . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6285: Level: intermediate
6287: .seealso: DMView()
6288: @*/
6289: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6290: {
6291: DM rdm;
6292: PetscDS prob;
6293: PetscFE fe;
6294: PetscScalar *r;
6295: PetscMPIInt rank;
6296: PetscInt dim, cStart, cEnd, c;
6300: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6301: DMClone(dm, &rdm);
6302: DMGetDimension(rdm, &dim);
6303: PetscFECreateDefault(rdm, dim, 1, PETSC_TRUE, NULL, -1, &fe);
6304: PetscObjectSetName((PetscObject) fe, "rank");
6305: DMGetDS(rdm, &prob);
6306: PetscDSSetDiscretization(prob, 0, (PetscObject) fe);
6307: PetscFEDestroy(&fe);
6308: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6309: DMCreateGlobalVector(rdm, ranks);
6310: PetscObjectSetName((PetscObject) *ranks, "partition");
6311: VecGetArray(*ranks, &r);
6312: for (c = cStart; c < cEnd; ++c) {
6313: PetscScalar *lr;
6315: DMPlexPointGlobalRef(rdm, c, r, &lr);
6316: *lr = rank;
6317: }
6318: VecRestoreArray(*ranks, &r);
6319: DMDestroy(&rdm);
6320: return(0);
6321: }
6323: /*@
6324: DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6326: Input Parameter:
6327: . dm - The DMPlex object
6329: Note: This is a useful diagnostic when creating meshes programmatically.
6331: Level: developer
6333: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6334: @*/
6335: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6336: {
6337: PetscSection coneSection, supportSection;
6338: const PetscInt *cone, *support;
6339: PetscInt coneSize, c, supportSize, s;
6340: PetscInt pStart, pEnd, p, csize, ssize;
6341: PetscErrorCode ierr;
6345: DMPlexGetConeSection(dm, &coneSection);
6346: DMPlexGetSupportSection(dm, &supportSection);
6347: /* Check that point p is found in the support of its cone points, and vice versa */
6348: DMPlexGetChart(dm, &pStart, &pEnd);
6349: for (p = pStart; p < pEnd; ++p) {
6350: DMPlexGetConeSize(dm, p, &coneSize);
6351: DMPlexGetCone(dm, p, &cone);
6352: for (c = 0; c < coneSize; ++c) {
6353: PetscBool dup = PETSC_FALSE;
6354: PetscInt d;
6355: for (d = c-1; d >= 0; --d) {
6356: if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6357: }
6358: DMPlexGetSupportSize(dm, cone[c], &supportSize);
6359: DMPlexGetSupport(dm, cone[c], &support);
6360: for (s = 0; s < supportSize; ++s) {
6361: if (support[s] == p) break;
6362: }
6363: if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6364: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6365: for (s = 0; s < coneSize; ++s) {
6366: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6367: }
6368: PetscPrintf(PETSC_COMM_SELF, "\n");
6369: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6370: for (s = 0; s < supportSize; ++s) {
6371: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6372: }
6373: PetscPrintf(PETSC_COMM_SELF, "\n");
6374: if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6375: else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6376: }
6377: }
6378: DMPlexGetSupportSize(dm, p, &supportSize);
6379: DMPlexGetSupport(dm, p, &support);
6380: for (s = 0; s < supportSize; ++s) {
6381: DMPlexGetConeSize(dm, support[s], &coneSize);
6382: DMPlexGetCone(dm, support[s], &cone);
6383: for (c = 0; c < coneSize; ++c) {
6384: if (cone[c] == p) break;
6385: }
6386: if (c >= coneSize) {
6387: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6388: for (c = 0; c < supportSize; ++c) {
6389: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6390: }
6391: PetscPrintf(PETSC_COMM_SELF, "\n");
6392: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6393: for (c = 0; c < coneSize; ++c) {
6394: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6395: }
6396: PetscPrintf(PETSC_COMM_SELF, "\n");
6397: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6398: }
6399: }
6400: }
6401: PetscSectionGetStorageSize(coneSection, &csize);
6402: PetscSectionGetStorageSize(supportSection, &ssize);
6403: if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6404: return(0);
6405: }
6407: /*@
6408: DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6410: Input Parameters:
6411: + dm - The DMPlex object
6412: . isSimplex - Are the cells simplices or tensor products
6413: - cellHeight - Normally 0
6415: Note: This is a useful diagnostic when creating meshes programmatically.
6417: Level: developer
6419: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6420: @*/
6421: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6422: {
6423: PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6428: DMGetDimension(dm, &dim);
6429: switch (dim) {
6430: case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6431: case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6432: case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6433: default:
6434: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6435: }
6436: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6437: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6438: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6439: cMax = cMax >= 0 ? cMax : cEnd;
6440: for (c = cStart; c < cMax; ++c) {
6441: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6443: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6444: for (cl = 0; cl < closureSize*2; cl += 2) {
6445: const PetscInt p = closure[cl];
6446: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6447: }
6448: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6449: if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D", c, coneSize, numCorners);
6450: }
6451: for (c = cMax; c < cEnd; ++c) {
6452: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6454: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6455: for (cl = 0; cl < closureSize*2; cl += 2) {
6456: const PetscInt p = closure[cl];
6457: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6458: }
6459: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6460: if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has %D vertices > %D", c, coneSize, numHybridCorners);
6461: }
6462: return(0);
6463: }
6465: /*@
6466: DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6468: Input Parameters:
6469: + dm - The DMPlex object
6470: . isSimplex - Are the cells simplices or tensor products
6471: - cellHeight - Normally 0
6473: Note: This is a useful diagnostic when creating meshes programmatically.
6475: Level: developer
6477: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6478: @*/
6479: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6480: {
6481: PetscInt pMax[4];
6482: PetscInt dim, vStart, vEnd, cStart, cEnd, c, h;
6487: DMGetDimension(dm, &dim);
6488: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6489: DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6490: for (h = cellHeight; h < dim; ++h) {
6491: DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6492: for (c = cStart; c < cEnd; ++c) {
6493: const PetscInt *cone, *ornt, *faces;
6494: PetscInt numFaces, faceSize, coneSize,f;
6495: PetscInt *closure = NULL, closureSize, cl, numCorners = 0;
6497: if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6498: DMPlexGetConeSize(dm, c, &coneSize);
6499: DMPlexGetCone(dm, c, &cone);
6500: DMPlexGetConeOrientation(dm, c, &ornt);
6501: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6502: for (cl = 0; cl < closureSize*2; cl += 2) {
6503: const PetscInt p = closure[cl];
6504: if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6505: }
6506: DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6507: if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6508: for (f = 0; f < numFaces; ++f) {
6509: PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6511: DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6512: for (cl = 0; cl < fclosureSize*2; cl += 2) {
6513: const PetscInt p = fclosure[cl];
6514: if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6515: }
6516: 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);
6517: for (v = 0; v < fnumCorners; ++v) {
6518: 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]);
6519: }
6520: DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6521: }
6522: DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6523: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6524: }
6525: }
6526: return(0);
6527: }
6529: /* Pointwise interpolation
6530: Just code FEM for now
6531: u^f = I u^c
6532: sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6533: u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6534: I_{ij} = psi^f_i phi^c_j
6535: */
6536: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6537: {
6538: PetscSection gsc, gsf;
6539: PetscInt m, n;
6540: void *ctx;
6541: DM cdm;
6542: PetscBool regular;
6546: DMGetDefaultGlobalSection(dmFine, &gsf);
6547: PetscSectionGetConstrainedStorageSize(gsf, &m);
6548: DMGetDefaultGlobalSection(dmCoarse, &gsc);
6549: PetscSectionGetConstrainedStorageSize(gsc, &n);
6551: MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6552: MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6553: MatSetType(*interpolation, dmCoarse->mattype);
6554: DMGetApplicationContext(dmFine, &ctx);
6556: DMGetCoarseDM(dmFine, &cdm);
6557: DMPlexGetRegularRefinement(dmFine, ®ular);
6558: if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6559: else {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6560: MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6561: /* Use naive scaling */
6562: DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6563: return(0);
6564: }
6566: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6567: {
6569: VecScatter ctx;
6572: DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6573: MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6574: VecScatterDestroy(&ctx);
6575: return(0);
6576: }
6578: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6579: {
6580: PetscSection gsc, gsf;
6581: PetscInt m, n;
6582: void *ctx;
6583: DM cdm;
6584: PetscBool regular;
6588: DMGetDefaultGlobalSection(dmFine, &gsf);
6589: PetscSectionGetConstrainedStorageSize(gsf, &m);
6590: DMGetDefaultGlobalSection(dmCoarse, &gsc);
6591: PetscSectionGetConstrainedStorageSize(gsc, &n);
6593: MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6594: MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6595: MatSetType(*mass, dmCoarse->mattype);
6596: DMGetApplicationContext(dmFine, &ctx);
6598: DMGetCoarseDM(dmFine, &cdm);
6599: DMPlexGetRegularRefinement(dmFine, ®ular);
6600: if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6601: else {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6602: MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6603: return(0);
6604: }
6606: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6607: {
6608: PetscSection section;
6609: IS *bcPoints, *bcComps;
6610: PetscBool *isFE;
6611: PetscInt *bcFields, *numComp, *numDof;
6612: PetscInt depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6613: PetscInt cStart, cEnd, cEndInterior;
6617: DMGetNumFields(dm, &numFields);
6618: /* FE and FV boundary conditions are handled slightly differently */
6619: PetscMalloc1(numFields, &isFE);
6620: for (f = 0; f < numFields; ++f) {
6621: PetscObject obj;
6622: PetscClassId id;
6624: DMGetField(dm, f, &obj);
6625: PetscObjectGetClassId(obj, &id);
6626: if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;}
6627: else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6628: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6629: }
6630: /* Allocate boundary point storage for FEM boundaries */
6631: DMPlexGetDepth(dm, &depth);
6632: DMGetDimension(dm, &dim);
6633: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6634: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6635: PetscDSGetNumBoundary(dm->prob, &numBd);
6636: if (!numFields && numBd) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "number of fields is zero and number of boundary conditions is nonzero (this should never happen)");
6637: for (bd = 0; bd < numBd; ++bd) {
6638: PetscInt field;
6639: DMBoundaryConditionType type;
6640: const char *labelName;
6641: DMLabel label;
6643: PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6644: DMGetLabel(dm,labelName,&label);
6645: if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6646: }
6647: /* Add ghost cell boundaries for FVM */
6648: for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6649: PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6650: /* Constrain ghost cells for FV */
6651: for (f = 0; f < numFields; ++f) {
6652: PetscInt *newidx, c;
6654: if (isFE[f] || cEndInterior < 0) continue;
6655: PetscMalloc1(cEnd-cEndInterior,&newidx);
6656: for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6657: bcFields[bc] = f;
6658: ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6659: }
6660: /* Handle FEM Dirichlet boundaries */
6661: for (bd = 0; bd < numBd; ++bd) {
6662: const char *bdLabel;
6663: DMLabel label;
6664: const PetscInt *comps;
6665: const PetscInt *values;
6666: PetscInt bd2, field, numComps, numValues;
6667: DMBoundaryConditionType type;
6668: PetscBool duplicate = PETSC_FALSE;
6670: PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6671: DMGetLabel(dm, bdLabel, &label);
6672: if (!isFE[field] || !label) continue;
6673: /* Only want to modify label once */
6674: for (bd2 = 0; bd2 < bd; ++bd2) {
6675: const char *bdname;
6676: PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6677: PetscStrcmp(bdname, bdLabel, &duplicate);
6678: if (duplicate) break;
6679: }
6680: if (!duplicate && (isFE[field])) {
6681: /* don't complete cells, which are just present to give orientation to the boundary */
6682: DMPlexLabelComplete(dm, label);
6683: }
6684: /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6685: if (type & DM_BC_ESSENTIAL) {
6686: PetscInt *newidx;
6687: PetscInt n, newn = 0, p, v;
6689: bcFields[bc] = field;
6690: if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6691: for (v = 0; v < numValues; ++v) {
6692: IS tmp;
6693: const PetscInt *idx;
6695: DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6696: if (!tmp) continue;
6697: ISGetLocalSize(tmp, &n);
6698: ISGetIndices(tmp, &idx);
6699: if (isFE[field]) {
6700: for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6701: } else {
6702: for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6703: }
6704: ISRestoreIndices(tmp, &idx);
6705: ISDestroy(&tmp);
6706: }
6707: PetscMalloc1(newn,&newidx);
6708: newn = 0;
6709: for (v = 0; v < numValues; ++v) {
6710: IS tmp;
6711: const PetscInt *idx;
6713: DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6714: if (!tmp) continue;
6715: ISGetLocalSize(tmp, &n);
6716: ISGetIndices(tmp, &idx);
6717: if (isFE[field]) {
6718: for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6719: } else {
6720: for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6721: }
6722: ISRestoreIndices(tmp, &idx);
6723: ISDestroy(&tmp);
6724: }
6725: ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6726: }
6727: }
6728: /* Handle discretization */
6729: PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6730: for (f = 0; f < numFields; ++f) {
6731: PetscObject obj;
6733: DMGetField(dm, f, &obj);
6734: if (isFE[f]) {
6735: PetscFE fe = (PetscFE) obj;
6736: const PetscInt *numFieldDof;
6737: PetscInt d;
6739: PetscFEGetNumComponents(fe, &numComp[f]);
6740: PetscFEGetNumDof(fe, &numFieldDof);
6741: for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6742: } else {
6743: PetscFV fv = (PetscFV) obj;
6745: PetscFVGetNumComponents(fv, &numComp[f]);
6746: numDof[f*(dim+1)+dim] = numComp[f];
6747: }
6748: }
6749: for (f = 0; f < numFields; ++f) {
6750: PetscInt d;
6751: for (d = 1; d < dim; ++d) {
6752: if ((numDof[f*(dim+1)+d] > 0) && (depth < dim)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces.");
6753: }
6754: }
6755: DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, §ion);
6756: for (f = 0; f < numFields; ++f) {
6757: PetscFE fe;
6758: const char *name;
6760: DMGetField(dm, f, (PetscObject *) &fe);
6761: PetscObjectGetName((PetscObject) fe, &name);
6762: PetscSectionSetFieldName(section, f, name);
6763: }
6764: DMSetDefaultSection(dm, section);
6765: PetscSectionDestroy(§ion);
6766: for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6767: PetscFree3(bcFields,bcPoints,bcComps);
6768: PetscFree2(numComp,numDof);
6769: PetscFree(isFE);
6770: return(0);
6771: }
6773: /*@
6774: DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6776: Input Parameter:
6777: . dm - The DMPlex object
6779: Output Parameter:
6780: . regular - The flag
6782: Level: intermediate
6784: .seealso: DMPlexSetRegularRefinement()
6785: @*/
6786: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6787: {
6791: *regular = ((DM_Plex *) dm->data)->regularRefinement;
6792: return(0);
6793: }
6795: /*@
6796: DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6798: Input Parameters:
6799: + dm - The DMPlex object
6800: - regular - The flag
6802: Level: intermediate
6804: .seealso: DMPlexGetRegularRefinement()
6805: @*/
6806: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6807: {
6810: ((DM_Plex *) dm->data)->regularRefinement = regular;
6811: return(0);
6812: }
6814: /* anchors */
6815: /*@
6816: DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to
6817: call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
6819: not collective
6821: Input Parameters:
6822: . dm - The DMPlex object
6824: Output Parameters:
6825: + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
6826: - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
6829: Level: intermediate
6831: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6832: @*/
6833: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6834: {
6835: DM_Plex *plex = (DM_Plex *)dm->data;
6840: if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6841: if (anchorSection) *anchorSection = plex->anchorSection;
6842: if (anchorIS) *anchorIS = plex->anchorIS;
6843: return(0);
6844: }
6846: /*@
6847: DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions,
6848: when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
6849: point's degrees of freedom to be a linear combination of other points' degrees of freedom.
6851: After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
6852: DMGetConstraints() and filling in the entries in the constraint matrix.
6854: collective on dm
6856: Input Parameters:
6857: + dm - The DMPlex object
6858: . 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).
6859: - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative).
6861: The reference counts of anchorSection and anchorIS are incremented.
6863: Level: intermediate
6865: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6866: @*/
6867: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6868: {
6869: DM_Plex *plex = (DM_Plex *)dm->data;
6870: PetscMPIInt result;
6875: if (anchorSection) {
6877: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6878: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6879: }
6880: if (anchorIS) {
6882: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6883: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6884: }
6886: PetscObjectReference((PetscObject)anchorSection);
6887: PetscSectionDestroy(&plex->anchorSection);
6888: plex->anchorSection = anchorSection;
6890: PetscObjectReference((PetscObject)anchorIS);
6891: ISDestroy(&plex->anchorIS);
6892: plex->anchorIS = anchorIS;
6894: #if defined(PETSC_USE_DEBUG)
6895: if (anchorIS && anchorSection) {
6896: PetscInt size, a, pStart, pEnd;
6897: const PetscInt *anchors;
6899: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6900: ISGetLocalSize(anchorIS,&size);
6901: ISGetIndices(anchorIS,&anchors);
6902: for (a = 0; a < size; a++) {
6903: PetscInt p;
6905: p = anchors[a];
6906: if (p >= pStart && p < pEnd) {
6907: PetscInt dof;
6909: PetscSectionGetDof(anchorSection,p,&dof);
6910: if (dof) {
6911: PetscErrorCode ierr2;
6913: ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6914: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6915: }
6916: }
6917: }
6918: ISRestoreIndices(anchorIS,&anchors);
6919: }
6920: #endif
6921: /* reset the generic constraints */
6922: DMSetDefaultConstraints(dm,NULL,NULL);
6923: return(0);
6924: }
6926: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6927: {
6928: PetscSection anchorSection;
6929: PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
6934: DMPlexGetAnchors(dm,&anchorSection,NULL);
6935: PetscSectionCreate(PETSC_COMM_SELF,cSec);
6936: PetscSectionGetNumFields(section,&numFields);
6937: if (numFields) {
6938: PetscInt f;
6939: PetscSectionSetNumFields(*cSec,numFields);
6941: for (f = 0; f < numFields; f++) {
6942: PetscInt numComp;
6944: PetscSectionGetFieldComponents(section,f,&numComp);
6945: PetscSectionSetFieldComponents(*cSec,f,numComp);
6946: }
6947: }
6948: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6949: PetscSectionGetChart(section,&sStart,&sEnd);
6950: pStart = PetscMax(pStart,sStart);
6951: pEnd = PetscMin(pEnd,sEnd);
6952: pEnd = PetscMax(pStart,pEnd);
6953: PetscSectionSetChart(*cSec,pStart,pEnd);
6954: for (p = pStart; p < pEnd; p++) {
6955: PetscSectionGetDof(anchorSection,p,&dof);
6956: if (dof) {
6957: PetscSectionGetDof(section,p,&dof);
6958: PetscSectionSetDof(*cSec,p,dof);
6959: for (f = 0; f < numFields; f++) {
6960: PetscSectionGetFieldDof(section,p,f,&dof);
6961: PetscSectionSetFieldDof(*cSec,p,f,dof);
6962: }
6963: }
6964: }
6965: PetscSectionSetUp(*cSec);
6966: return(0);
6967: }
6969: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6970: {
6971: PetscSection aSec;
6972: PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6973: const PetscInt *anchors;
6974: PetscInt numFields, f;
6975: IS aIS;
6980: PetscSectionGetStorageSize(cSec, &m);
6981: PetscSectionGetStorageSize(section, &n);
6982: MatCreate(PETSC_COMM_SELF,cMat);
6983: MatSetSizes(*cMat,m,n,m,n);
6984: MatSetType(*cMat,MATSEQAIJ);
6985: DMPlexGetAnchors(dm,&aSec,&aIS);
6986: ISGetIndices(aIS,&anchors);
6987: /* cSec will be a subset of aSec and section */
6988: PetscSectionGetChart(cSec,&pStart,&pEnd);
6989: PetscMalloc1(m+1,&i);
6990: i[0] = 0;
6991: PetscSectionGetNumFields(section,&numFields);
6992: for (p = pStart; p < pEnd; p++) {
6993: PetscInt rDof, rOff, r;
6995: PetscSectionGetDof(aSec,p,&rDof);
6996: if (!rDof) continue;
6997: PetscSectionGetOffset(aSec,p,&rOff);
6998: if (numFields) {
6999: for (f = 0; f < numFields; f++) {
7000: annz = 0;
7001: for (r = 0; r < rDof; r++) {
7002: a = anchors[rOff + r];
7003: PetscSectionGetFieldDof(section,a,f,&aDof);
7004: annz += aDof;
7005: }
7006: PetscSectionGetFieldDof(cSec,p,f,&dof);
7007: PetscSectionGetFieldOffset(cSec,p,f,&off);
7008: for (q = 0; q < dof; q++) {
7009: i[off + q + 1] = i[off + q] + annz;
7010: }
7011: }
7012: }
7013: else {
7014: annz = 0;
7015: for (q = 0; q < dof; q++) {
7016: a = anchors[off + q];
7017: PetscSectionGetDof(section,a,&aDof);
7018: annz += aDof;
7019: }
7020: PetscSectionGetDof(cSec,p,&dof);
7021: PetscSectionGetOffset(cSec,p,&off);
7022: for (q = 0; q < dof; q++) {
7023: i[off + q + 1] = i[off + q] + annz;
7024: }
7025: }
7026: }
7027: nnz = i[m];
7028: PetscMalloc1(nnz,&j);
7029: offset = 0;
7030: for (p = pStart; p < pEnd; p++) {
7031: if (numFields) {
7032: for (f = 0; f < numFields; f++) {
7033: PetscSectionGetFieldDof(cSec,p,f,&dof);
7034: for (q = 0; q < dof; q++) {
7035: PetscInt rDof, rOff, r;
7036: PetscSectionGetDof(aSec,p,&rDof);
7037: PetscSectionGetOffset(aSec,p,&rOff);
7038: for (r = 0; r < rDof; r++) {
7039: PetscInt s;
7041: a = anchors[rOff + r];
7042: PetscSectionGetFieldDof(section,a,f,&aDof);
7043: PetscSectionGetFieldOffset(section,a,f,&aOff);
7044: for (s = 0; s < aDof; s++) {
7045: j[offset++] = aOff + s;
7046: }
7047: }
7048: }
7049: }
7050: }
7051: else {
7052: PetscSectionGetDof(cSec,p,&dof);
7053: for (q = 0; q < dof; q++) {
7054: PetscInt rDof, rOff, r;
7055: PetscSectionGetDof(aSec,p,&rDof);
7056: PetscSectionGetOffset(aSec,p,&rOff);
7057: for (r = 0; r < rDof; r++) {
7058: PetscInt s;
7060: a = anchors[rOff + r];
7061: PetscSectionGetDof(section,a,&aDof);
7062: PetscSectionGetOffset(section,a,&aOff);
7063: for (s = 0; s < aDof; s++) {
7064: j[offset++] = aOff + s;
7065: }
7066: }
7067: }
7068: }
7069: }
7070: MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7071: PetscFree(i);
7072: PetscFree(j);
7073: ISRestoreIndices(aIS,&anchors);
7074: return(0);
7075: }
7077: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7078: {
7079: DM_Plex *plex = (DM_Plex *)dm->data;
7080: PetscSection anchorSection, section, cSec;
7081: Mat cMat;
7086: DMPlexGetAnchors(dm,&anchorSection,NULL);
7087: if (anchorSection) {
7088: PetscDS ds;
7089: PetscInt nf;
7091: DMGetDefaultSection(dm,§ion);
7092: DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7093: DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7094: DMGetDS(dm,&ds);
7095: PetscDSGetNumFields(ds,&nf);
7096: if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7097: DMSetDefaultConstraints(dm,cSec,cMat);
7098: PetscSectionDestroy(&cSec);
7099: MatDestroy(&cMat);
7100: }
7101: return(0);
7102: }