Actual source code: plex.c
petsc-3.10.5 2019-03-28
1: #include <petsc/private/dmpleximpl.h>
2: #include <petsc/private/isimpl.h>
3: #include <petsc/private/vecimpl.h>
4: #include <petsc/private/glvisvecimpl.h>
5: #include <petscsf.h>
6: #include <petscds.h>
7: #include <petscdraw.h>
8: #include <petscdmfield.h>
10: /* Logging support */
11: PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;
13: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
15: /*@
16: DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells.
17: 3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D.
19: Collective
21: Input Parameters:
22: . dm - The DMPlex object
24: Output Parameters:
25: . dmRefined - The refined DMPlex object
27: Note: Returns NULL if the mesh is already a tensor product mesh.
29: Level: intermediate
31: .seealso: DMPlexCreate(), DMPlexSetRefinementUniform()
32: @*/
33: PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined)
34: {
35: PetscInt dim, cMax, fMax, cStart, cEnd, coneSize;
36: CellRefiner cellRefiner;
37: PetscBool lop, allnoop, localized;
38: PetscErrorCode ierr;
43: DMGetDimension(dm, &dim);
44: DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
45: DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
46: if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
47: else {
48: DMPlexGetConeSize(dm,cStart,&coneSize);
49: switch (dim) {
50: case 1:
51: cellRefiner = REFINER_NOOP;
52: break;
53: case 2:
54: switch (coneSize) {
55: case 3:
56: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
57: else cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
58: break;
59: case 4:
60: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
61: else cellRefiner = REFINER_NOOP;
62: break;
63: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
64: }
65: break;
66: case 3:
67: switch (coneSize) {
68: case 4:
69: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
70: else cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
71: break;
72: case 5:
73: if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
74: else cellRefiner = REFINER_NOOP;
75: break;
76: case 6:
77: if (cMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Simplex2Tensor in 3D with Hybrid mesh not yet done");
78: cellRefiner = REFINER_NOOP;
79: break;
80: default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
81: }
82: break;
83: default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
84: }
85: }
86: /* return if we don't need to refine */
87: lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
88: MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
89: if (allnoop) {
90: *dmRefined = NULL;
91: return(0);
92: }
93: DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
94: DMCopyBoundary(dm, *dmRefined);
95: DMGetCoordinatesLocalized(dm, &localized);
96: if (localized) {
97: DMLocalizeCoordinates(*dmRefined);
98: }
99: return(0);
100: }
102: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
103: {
104: PetscInt dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior;
105: PetscInt vcdof[2] = {0,0}, globalvcdof[2];
109: *ft = PETSC_VTK_POINT_FIELD;
110: DMGetDimension(dm, &dim);
111: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
112: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
113: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
114: cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
115: PetscSectionGetChart(section, &pStart, &pEnd);
116: if (field >= 0) {
117: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);}
118: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);}
119: } else {
120: if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vcdof[0]);}
121: if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &vcdof[1]);}
122: }
123: MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
124: if (globalvcdof[0]) {
125: *sStart = vStart;
126: *sEnd = vEnd;
127: if (globalvcdof[0] == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
128: else *ft = PETSC_VTK_POINT_FIELD;
129: } else if (globalvcdof[1]) {
130: *sStart = cStart;
131: *sEnd = cEnd;
132: if (globalvcdof[1] == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
133: else *ft = PETSC_VTK_CELL_FIELD;
134: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
135: return(0);
136: }
138: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
139: {
140: DM dm;
141: PetscSection s;
142: PetscDraw draw, popup;
143: DM cdm;
144: PetscSection coordSection;
145: Vec coordinates;
146: const PetscScalar *coords, *array;
147: PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
148: PetscReal vbound[2], time;
149: PetscBool isnull, flg;
150: PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
151: const char *name;
152: char title[PETSC_MAX_PATH_LEN];
153: PetscErrorCode ierr;
156: PetscViewerDrawGetDraw(viewer, 0, &draw);
157: PetscDrawIsNull(draw, &isnull);
158: if (isnull) return(0);
160: VecGetDM(v, &dm);
161: DMGetCoordinateDim(dm, &dim);
162: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
163: DMGetSection(dm, &s);
164: PetscSectionGetNumFields(s, &Nf);
165: DMGetCoarsenLevel(dm, &level);
166: DMGetCoordinateDM(dm, &cdm);
167: DMGetSection(cdm, &coordSection);
168: DMGetCoordinatesLocal(dm, &coordinates);
169: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
170: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
172: PetscObjectGetName((PetscObject) v, &name);
173: DMGetOutputSequenceNumber(dm, &step, &time);
175: VecGetLocalSize(coordinates, &N);
176: VecGetArrayRead(coordinates, &coords);
177: for (c = 0; c < N; c += dim) {
178: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
179: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
180: }
181: VecRestoreArrayRead(coordinates, &coords);
182: PetscDrawClear(draw);
184: /* Could implement something like DMDASelectFields() */
185: for (f = 0; f < Nf; ++f) {
186: DM fdm = dm;
187: Vec fv = v;
188: IS fis;
189: char prefix[PETSC_MAX_PATH_LEN];
190: const char *fname;
192: PetscSectionGetFieldComponents(s, f, &Nc);
193: PetscSectionGetFieldName(s, f, &fname);
195: if (v->hdr.prefix) {PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));}
196: else {prefix[0] = '\0';}
197: if (Nf > 1) {
198: DMCreateSubDM(dm, 1, &f, &fis, &fdm);
199: VecGetSubVector(v, fis, &fv);
200: PetscStrlcat(prefix, fname,sizeof(prefix));
201: PetscStrlcat(prefix, "_",sizeof(prefix));
202: }
203: for (comp = 0; comp < Nc; ++comp, ++w) {
204: PetscInt nmax = 2;
206: PetscViewerDrawGetDraw(viewer, w, &draw);
207: if (Nc > 1) {PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);}
208: else {PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);}
209: PetscDrawSetTitle(draw, title);
211: /* TODO Get max and min only for this component */
212: PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
213: if (!flg) {
214: VecMin(fv, NULL, &vbound[0]);
215: VecMax(fv, NULL, &vbound[1]);
216: if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
217: }
218: PetscDrawGetPopup(draw, &popup);
219: PetscDrawScalePopup(popup, vbound[0], vbound[1]);
220: PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
222: VecGetArrayRead(fv, &array);
223: for (c = cStart; c < cEnd; ++c) {
224: PetscScalar *coords = NULL, *a = NULL;
225: PetscInt numCoords, color[4] = {-1,-1,-1,-1};
227: DMPlexPointLocalRead(fdm, c, array, &a);
228: if (a) {
229: color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
230: color[1] = color[2] = color[3] = color[0];
231: } else {
232: PetscScalar *vals = NULL;
233: PetscInt numVals, va;
235: DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
236: if (numVals % Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %D does not divide the number of values in the closure %D", Nc, numVals);
237: switch (numVals/Nc) {
238: case 3: /* P1 Triangle */
239: case 4: /* P1 Quadrangle */
240: for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
241: break;
242: case 6: /* P2 Triangle */
243: case 8: /* P2 Quadrangle */
244: for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
245: break;
246: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
247: }
248: DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
249: }
250: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
251: switch (numCoords) {
252: case 6:
253: PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
254: break;
255: case 8:
256: PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
257: PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0]);
258: break;
259: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
260: }
261: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
262: }
263: VecRestoreArrayRead(fv, &array);
264: PetscDrawFlush(draw);
265: PetscDrawPause(draw);
266: PetscDrawSave(draw);
267: }
268: if (Nf > 1) {
269: VecRestoreSubVector(v, fis, &fv);
270: ISDestroy(&fis);
271: DMDestroy(&fdm);
272: }
273: }
274: return(0);
275: }
277: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
278: {
279: DM dm;
280: Vec locv;
281: const char *name;
282: PetscSection section;
283: PetscInt pStart, pEnd;
284: PetscViewerVTKFieldType ft;
285: PetscErrorCode ierr;
288: VecGetDM(v, &dm);
289: DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
290: PetscObjectGetName((PetscObject) v, &name);
291: PetscObjectSetName((PetscObject) locv, name);
292: VecCopy(v, locv);
293: DMGetSection(dm, §ion);
294: DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
295: PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, PETSC_TRUE,(PetscObject) locv);
296: return(0);
297: }
299: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
300: {
301: DM dm;
302: PetscBool isvtk, ishdf5, isdraw, isglvis;
306: VecGetDM(v, &dm);
307: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
308: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
309: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
310: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
311: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
312: if (isvtk || ishdf5 || isdraw || isglvis) {
313: PetscInt i,numFields;
314: PetscObject fe;
315: PetscBool fem = PETSC_FALSE;
316: Vec locv = v;
317: const char *name;
318: PetscInt step;
319: PetscReal time;
321: DMGetNumFields(dm, &numFields);
322: for (i=0; i<numFields; i++) {
323: DMGetField(dm, i, &fe);
324: if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
325: }
326: if (fem) {
327: DMGetLocalVector(dm, &locv);
328: PetscObjectGetName((PetscObject) v, &name);
329: PetscObjectSetName((PetscObject) locv, name);
330: VecCopy(v, locv);
331: DMGetOutputSequenceNumber(dm, NULL, &time);
332: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
333: }
334: if (isvtk) {
335: VecView_Plex_Local_VTK(locv, viewer);
336: } else if (ishdf5) {
337: #if defined(PETSC_HAVE_HDF5)
338: VecView_Plex_Local_HDF5_Internal(locv, viewer);
339: #else
340: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
341: #endif
342: } else if (isdraw) {
343: VecView_Plex_Local_Draw(locv, viewer);
344: } else if (isglvis) {
345: DMGetOutputSequenceNumber(dm, &step, NULL);
346: PetscViewerGLVisSetSnapId(viewer, step);
347: VecView_GLVis(locv, viewer);
348: }
349: if (fem) {DMRestoreLocalVector(dm, &locv);}
350: } else {
351: PetscBool isseq;
353: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
354: if (isseq) {VecView_Seq(v, viewer);}
355: else {VecView_MPI(v, viewer);}
356: }
357: return(0);
358: }
360: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
361: {
362: DM dm;
363: PetscBool isvtk, ishdf5, isdraw, isglvis;
367: VecGetDM(v, &dm);
368: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
369: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
370: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
371: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
372: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
373: if (isvtk || isdraw || isglvis) {
374: Vec locv;
375: const char *name;
377: DMGetLocalVector(dm, &locv);
378: PetscObjectGetName((PetscObject) v, &name);
379: PetscObjectSetName((PetscObject) locv, name);
380: DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
381: DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
382: VecView_Plex_Local(locv, viewer);
383: DMRestoreLocalVector(dm, &locv);
384: } else if (ishdf5) {
385: #if defined(PETSC_HAVE_HDF5)
386: VecView_Plex_HDF5_Internal(v, viewer);
387: #else
388: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
389: #endif
390: } else {
391: PetscBool isseq;
393: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
394: if (isseq) {VecView_Seq(v, viewer);}
395: else {VecView_MPI(v, viewer);}
396: }
397: return(0);
398: }
400: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
401: {
402: DM dm;
403: MPI_Comm comm;
404: PetscViewerFormat format;
405: Vec v;
406: PetscBool isvtk, ishdf5;
407: PetscErrorCode ierr;
410: VecGetDM(originalv, &dm);
411: PetscObjectGetComm((PetscObject) originalv, &comm);
412: if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
413: PetscViewerGetFormat(viewer, &format);
414: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
415: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
416: if (format == PETSC_VIEWER_NATIVE) {
417: const char *vecname;
418: PetscInt n, nroots;
420: if (dm->sfNatural) {
421: VecGetLocalSize(originalv, &n);
422: PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
423: if (n == nroots) {
424: DMGetGlobalVector(dm, &v);
425: DMPlexGlobalToNaturalBegin(dm, originalv, v);
426: DMPlexGlobalToNaturalEnd(dm, originalv, v);
427: PetscObjectGetName((PetscObject) originalv, &vecname);
428: PetscObjectSetName((PetscObject) v, vecname);
429: } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
430: } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
431: } else {
432: /* we are viewing a natural DMPlex vec. */
433: v = originalv;
434: }
435: if (ishdf5) {
436: #if defined(PETSC_HAVE_HDF5)
437: VecView_Plex_HDF5_Native_Internal(v, viewer);
438: #else
439: SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
440: #endif
441: } else if (isvtk) {
442: SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
443: } else {
444: PetscBool isseq;
446: PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
447: if (isseq) {VecView_Seq(v, viewer);}
448: else {VecView_MPI(v, viewer);}
449: }
450: if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
451: return(0);
452: }
454: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
455: {
456: DM dm;
457: PetscBool ishdf5;
461: VecGetDM(v, &dm);
462: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
463: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
464: if (ishdf5) {
465: DM dmBC;
466: Vec gv;
467: const char *name;
469: DMGetOutputDM(dm, &dmBC);
470: DMGetGlobalVector(dmBC, &gv);
471: PetscObjectGetName((PetscObject) v, &name);
472: PetscObjectSetName((PetscObject) gv, name);
473: VecLoad_Default(gv, viewer);
474: DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
475: DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
476: DMRestoreGlobalVector(dmBC, &gv);
477: } else {
478: VecLoad_Default(v, viewer);
479: }
480: return(0);
481: }
483: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
484: {
485: DM dm;
486: PetscBool ishdf5;
490: VecGetDM(v, &dm);
491: if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
492: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
493: if (ishdf5) {
494: #if defined(PETSC_HAVE_HDF5)
495: VecLoad_Plex_HDF5_Internal(v, viewer);
496: #else
497: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
498: #endif
499: } else {
500: VecLoad_Default(v, viewer);
501: }
502: return(0);
503: }
505: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
506: {
507: DM dm;
508: PetscViewerFormat format;
509: PetscBool ishdf5;
510: PetscErrorCode ierr;
513: VecGetDM(originalv, &dm);
514: if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
515: PetscViewerGetFormat(viewer, &format);
516: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
517: if (format == PETSC_VIEWER_NATIVE) {
518: if (dm->sfNatural) {
519: if (ishdf5) {
520: #if defined(PETSC_HAVE_HDF5)
521: Vec v;
522: const char *vecname;
524: DMGetGlobalVector(dm, &v);
525: PetscObjectGetName((PetscObject) originalv, &vecname);
526: PetscObjectSetName((PetscObject) v, vecname);
527: VecLoad_Plex_HDF5_Native_Internal(v, viewer);
528: DMPlexNaturalToGlobalBegin(dm, v, originalv);
529: DMPlexNaturalToGlobalEnd(dm, v, originalv);
530: DMRestoreGlobalVector(dm, &v);
531: #else
532: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
533: #endif
534: } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
535: }
536: }
537: return(0);
538: }
540: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
541: {
542: PetscSection coordSection;
543: Vec coordinates;
544: DMLabel depthLabel;
545: const char *name[4];
546: const PetscScalar *a;
547: PetscInt dim, pStart, pEnd, cStart, cEnd, c;
548: PetscErrorCode ierr;
551: DMGetDimension(dm, &dim);
552: DMGetCoordinatesLocal(dm, &coordinates);
553: DMGetCoordinateSection(dm, &coordSection);
554: DMPlexGetDepthLabel(dm, &depthLabel);
555: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
556: PetscSectionGetChart(coordSection, &pStart, &pEnd);
557: VecGetArrayRead(coordinates, &a);
558: name[0] = "vertex";
559: name[1] = "edge";
560: name[dim-1] = "face";
561: name[dim] = "cell";
562: for (c = cStart; c < cEnd; ++c) {
563: PetscInt *closure = NULL;
564: PetscInt closureSize, cl;
566: PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);
567: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
568: PetscViewerASCIIPushTab(viewer);
569: for (cl = 0; cl < closureSize*2; cl += 2) {
570: PetscInt point = closure[cl], depth, dof, off, d, p;
572: if ((point < pStart) || (point >= pEnd)) continue;
573: PetscSectionGetDof(coordSection, point, &dof);
574: if (!dof) continue;
575: DMLabelGetValue(depthLabel, point, &depth);
576: PetscSectionGetOffset(coordSection, point, &off);
577: PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
578: for (p = 0; p < dof/dim; ++p) {
579: PetscViewerASCIIPrintf(viewer, " (");
580: for (d = 0; d < dim; ++d) {
581: if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
582: PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
583: }
584: PetscViewerASCIIPrintf(viewer, ")");
585: }
586: PetscViewerASCIIPrintf(viewer, "\n");
587: }
588: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
589: PetscViewerASCIIPopTab(viewer);
590: }
591: VecRestoreArrayRead(coordinates, &a);
592: return(0);
593: }
595: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
596: {
597: DM_Plex *mesh = (DM_Plex*) dm->data;
598: DM cdm;
599: DMLabel markers;
600: PetscSection coordSection;
601: Vec coordinates;
602: PetscViewerFormat format;
603: PetscErrorCode ierr;
606: DMGetCoordinateDM(dm, &cdm);
607: DMGetSection(cdm, &coordSection);
608: DMGetCoordinatesLocal(dm, &coordinates);
609: PetscViewerGetFormat(viewer, &format);
610: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
611: const char *name;
612: PetscInt dim, cellHeight, maxConeSize, maxSupportSize;
613: PetscInt pStart, pEnd, p;
614: PetscMPIInt rank, size;
616: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
617: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
618: PetscObjectGetName((PetscObject) dm, &name);
619: DMPlexGetChart(dm, &pStart, &pEnd);
620: DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
621: DMGetDimension(dm, &dim);
622: DMPlexGetVTKCellHeight(dm, &cellHeight);
623: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
624: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
625: if (cellHeight) {PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);}
626: PetscViewerASCIIPrintf(viewer, "Supports:\n", name);
627: PetscViewerASCIIPushSynchronized(viewer);
628: PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);
629: for (p = pStart; p < pEnd; ++p) {
630: PetscInt dof, off, s;
632: PetscSectionGetDof(mesh->supportSection, p, &dof);
633: PetscSectionGetOffset(mesh->supportSection, p, &off);
634: for (s = off; s < off+dof; ++s) {
635: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
636: }
637: }
638: PetscViewerFlush(viewer);
639: PetscViewerASCIIPrintf(viewer, "Cones:\n", name);
640: PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);
641: for (p = pStart; p < pEnd; ++p) {
642: PetscInt dof, off, c;
644: PetscSectionGetDof(mesh->coneSection, p, &dof);
645: PetscSectionGetOffset(mesh->coneSection, p, &off);
646: for (c = off; c < off+dof; ++c) {
647: PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
648: }
649: }
650: PetscViewerFlush(viewer);
651: PetscViewerASCIIPopSynchronized(viewer);
652: PetscSectionGetChart(coordSection, &pStart, NULL);
653: if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
654: DMGetLabel(dm, "marker", &markers);
655: DMLabelView(markers,viewer);
656: if (size > 1) {
657: PetscSF sf;
659: DMGetPointSF(dm, &sf);
660: PetscSFView(sf, viewer);
661: }
662: PetscViewerFlush(viewer);
663: } else if (format == PETSC_VIEWER_ASCII_LATEX) {
664: const char *name, *color;
665: const char *defcolors[3] = {"gray", "orange", "green"};
666: const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
667: PetscReal scale = 2.0;
668: PetscBool useNumbers = PETSC_TRUE, useLabels, useColors;
669: double tcoords[3];
670: PetscScalar *coords;
671: PetscInt numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
672: PetscMPIInt rank, size;
673: char **names, **colors, **lcolors;
674: PetscBool plotEdges, flg;
676: DMGetDimension(dm, &dim);
677: DMPlexGetDepth(dm, &depth);
678: DMGetNumLabels(dm, &numLabels);
679: numLabels = PetscMax(numLabels, 10);
680: numColors = 10;
681: numLColors = 10;
682: PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
683: PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
684: PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
685: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
686: if (!useLabels) numLabels = 0;
687: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
688: if (!useColors) {
689: numColors = 3;
690: for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
691: }
692: PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
693: if (!useColors) {
694: numLColors = 4;
695: for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
696: }
697: plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
698: PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);
699: if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
700: if (depth < dim) plotEdges = PETSC_FALSE;
701: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
702: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
703: PetscObjectGetName((PetscObject) dm, &name);
704: PetscViewerASCIIPrintf(viewer, "\
705: \\documentclass[tikz]{standalone}\n\n\
706: \\usepackage{pgflibraryshapes}\n\
707: \\usetikzlibrary{backgrounds}\n\
708: \\usetikzlibrary{arrows}\n\
709: \\begin{document}\n");
710: if (size > 1) {
711: PetscViewerASCIIPrintf(viewer, "%s for process ", name);
712: for (p = 0; p < size; ++p) {
713: if (p > 0 && p == size-1) {
714: PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
715: } else if (p > 0) {
716: PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
717: }
718: PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
719: }
720: PetscViewerASCIIPrintf(viewer, ".\n\n\n");
721: }
722: PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);
723: /* Plot vertices */
724: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
725: VecGetArray(coordinates, &coords);
726: PetscViewerASCIIPushSynchronized(viewer);
727: for (v = vStart; v < vEnd; ++v) {
728: PetscInt off, dof, d;
729: PetscBool isLabeled = PETSC_FALSE;
731: PetscSectionGetDof(coordSection, v, &dof);
732: PetscSectionGetOffset(coordSection, v, &off);
733: PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
734: if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
735: for (d = 0; d < dof; ++d) {
736: tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
737: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
738: }
739: /* Rotate coordinates since PGF makes z point out of the page instead of up */
740: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
741: for (d = 0; d < dof; ++d) {
742: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
743: PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
744: }
745: color = colors[rank%numColors];
746: for (l = 0; l < numLabels; ++l) {
747: PetscInt val;
748: DMGetLabelValue(dm, names[l], v, &val);
749: if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
750: }
751: if (useNumbers) {
752: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
753: } else {
754: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
755: }
756: }
757: VecRestoreArray(coordinates, &coords);
758: PetscViewerFlush(viewer);
759: /* Plot cells */
760: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
761: if (dim == 3 || !useNumbers) {
762: for (e = eStart; e < eEnd; ++e) {
763: const PetscInt *cone;
765: color = colors[rank%numColors];
766: for (l = 0; l < numLabels; ++l) {
767: PetscInt val;
768: DMGetLabelValue(dm, names[l], e, &val);
769: if (val >= 0) {color = lcolors[l%numLColors]; break;}
770: }
771: DMPlexGetCone(dm, e, &cone);
772: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
773: }
774: } else {
775: for (c = cStart; c < cEnd; ++c) {
776: PetscInt *closure = NULL;
777: PetscInt closureSize, firstPoint = -1;
779: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
780: PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
781: for (p = 0; p < closureSize*2; p += 2) {
782: const PetscInt point = closure[p];
784: if ((point < vStart) || (point >= vEnd)) continue;
785: if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
786: PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
787: if (firstPoint < 0) firstPoint = point;
788: }
789: /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
790: PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
791: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
792: }
793: }
794: VecGetArray(coordinates, &coords);
795: for (c = cStart; c < cEnd; ++c) {
796: double ccoords[3] = {0.0, 0.0, 0.0};
797: PetscBool isLabeled = PETSC_FALSE;
798: PetscInt *closure = NULL;
799: PetscInt closureSize, dof, d, n = 0;
801: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
802: PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
803: for (p = 0; p < closureSize*2; p += 2) {
804: const PetscInt point = closure[p];
805: PetscInt off;
807: if ((point < vStart) || (point >= vEnd)) continue;
808: PetscSectionGetDof(coordSection, point, &dof);
809: PetscSectionGetOffset(coordSection, point, &off);
810: for (d = 0; d < dof; ++d) {
811: tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
812: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
813: }
814: /* Rotate coordinates since PGF makes z point out of the page instead of up */
815: if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
816: for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
817: ++n;
818: }
819: for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
820: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
821: for (d = 0; d < dof; ++d) {
822: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
823: PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d]);
824: }
825: color = colors[rank%numColors];
826: for (l = 0; l < numLabels; ++l) {
827: PetscInt val;
828: DMGetLabelValue(dm, names[l], c, &val);
829: if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
830: }
831: if (useNumbers) {
832: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);
833: } else {
834: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);
835: }
836: }
837: VecRestoreArray(coordinates, &coords);
838: /* Plot edges */
839: if (depth > 1 || plotEdges) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
840: if (plotEdges) {
841: VecGetArray(coordinates, &coords);
842: PetscViewerASCIIPrintf(viewer, "\\path\n");
843: for (e = eStart; e < eEnd; ++e) {
844: const PetscInt *cone;
845: PetscInt coneSize, offA, offB, dof, d;
847: DMPlexGetConeSize(dm, e, &coneSize);
848: if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
849: DMPlexGetCone(dm, e, &cone);
850: PetscSectionGetDof(coordSection, cone[0], &dof);
851: PetscSectionGetOffset(coordSection, cone[0], &offA);
852: PetscSectionGetOffset(coordSection, cone[1], &offB);
853: PetscViewerASCIISynchronizedPrintf(viewer, "(");
854: for (d = 0; d < dof; ++d) {
855: tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
856: tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
857: }
858: /* Rotate coordinates since PGF makes z point out of the page instead of up */
859: if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
860: for (d = 0; d < dof; ++d) {
861: if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
862: PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
863: }
864: color = colors[rank%numColors];
865: for (l = 0; l < numLabels; ++l) {
866: PetscInt val;
867: DMGetLabelValue(dm, names[l], v, &val);
868: if (val >= 0) {color = lcolors[l%numLColors]; break;}
869: }
870: PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
871: }
872: VecRestoreArray(coordinates, &coords);
873: PetscViewerFlush(viewer);
874: PetscViewerASCIIPrintf(viewer, "(0,0);\n");
875: }
876: PetscViewerFlush(viewer);
877: PetscViewerASCIIPopSynchronized(viewer);
878: PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
879: PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
880: for (l = 0; l < numLabels; ++l) {PetscFree(names[l]);}
881: for (c = 0; c < numColors; ++c) {PetscFree(colors[c]);}
882: for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
883: PetscFree3(names, colors, lcolors);
884: } else {
885: MPI_Comm comm;
886: PetscInt *sizes, *hybsizes;
887: PetscInt locDepth, depth, cellHeight, dim, d, pMax[4];
888: PetscInt pStart, pEnd, p;
889: PetscInt numLabels, l;
890: const char *name;
891: PetscMPIInt size;
893: PetscObjectGetComm((PetscObject)dm,&comm);
894: MPI_Comm_size(comm, &size);
895: DMGetDimension(dm, &dim);
896: DMPlexGetVTKCellHeight(dm, &cellHeight);
897: PetscObjectGetName((PetscObject) dm, &name);
898: if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
899: else {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
900: if (cellHeight) {PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);}
901: DMPlexGetDepth(dm, &locDepth);
902: MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
903: DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);
904: PetscCalloc2(size,&sizes,size,&hybsizes);
905: if (depth == 1) {
906: DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
907: pEnd = pEnd - pStart;
908: pMax[0] -= pStart;
909: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
910: MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
911: PetscViewerASCIIPrintf(viewer, " %d-cells:", 0);
912: for (p = 0; p < size; ++p) {
913: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
914: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
915: }
916: PetscViewerASCIIPrintf(viewer, "\n");
917: DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
918: pEnd = pEnd - pStart;
919: pMax[depth] -= pStart;
920: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
921: MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
922: PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);
923: for (p = 0; p < size; ++p) {
924: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
925: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
926: }
927: PetscViewerASCIIPrintf(viewer, "\n");
928: } else {
929: PetscMPIInt rank;
930: MPI_Comm_rank(comm, &rank);
931: for (d = 0; d <= dim; d++) {
932: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
933: pEnd -= pStart;
934: pMax[d] -= pStart;
935: MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
936: MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
937: PetscViewerASCIIPrintf(viewer, " %D-cells:", d);
938: for (p = 0; p < size; ++p) {
939: if (!rank) {
940: if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
941: else {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
942: }
943: }
944: PetscViewerASCIIPrintf(viewer, "\n");
945: }
946: }
947: PetscFree2(sizes,hybsizes);
948: DMGetNumLabels(dm, &numLabels);
949: if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
950: for (l = 0; l < numLabels; ++l) {
951: DMLabel label;
952: const char *name;
953: IS valueIS;
954: const PetscInt *values;
955: PetscInt numValues, v;
957: DMGetLabelName(dm, l, &name);
958: DMGetLabel(dm, name, &label);
959: DMLabelGetNumValues(label, &numValues);
960: PetscViewerASCIIPrintf(viewer, " %s: %D strata with value/size (", name, numValues);
961: DMLabelGetValueIS(label, &valueIS);
962: ISGetIndices(valueIS, &values);
963: PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
964: for (v = 0; v < numValues; ++v) {
965: PetscInt size;
967: DMLabelGetStratumSize(label, values[v], &size);
968: if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
969: PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
970: }
971: PetscViewerASCIIPrintf(viewer, ")\n");
972: PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
973: ISRestoreIndices(valueIS, &values);
974: ISDestroy(&valueIS);
975: }
976: DMGetCoarseDM(dm, &cdm);
977: if (cdm) {
978: PetscViewerASCIIPushTab(viewer);
979: DMPlexView_Ascii(cdm, viewer);
980: PetscViewerASCIIPopTab(viewer);
981: }
982: }
983: return(0);
984: }
986: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
987: {
988: PetscDraw draw;
989: DM cdm;
990: PetscSection coordSection;
991: Vec coordinates;
992: const PetscScalar *coords;
993: PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
994: PetscBool isnull;
995: PetscInt dim, vStart, vEnd, cStart, cEnd, c, N;
996: PetscMPIInt rank;
997: PetscErrorCode ierr;
1000: DMGetCoordinateDim(dm, &dim);
1001: if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1002: DMGetCoordinateDM(dm, &cdm);
1003: DMGetSection(cdm, &coordSection);
1004: DMGetCoordinatesLocal(dm, &coordinates);
1005: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1006: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1008: PetscViewerDrawGetDraw(viewer, 0, &draw);
1009: PetscDrawIsNull(draw, &isnull);
1010: if (isnull) return(0);
1011: PetscDrawSetTitle(draw, "Mesh");
1013: VecGetLocalSize(coordinates, &N);
1014: VecGetArrayRead(coordinates, &coords);
1015: for (c = 0; c < N; c += dim) {
1016: bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1017: bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1018: }
1019: VecRestoreArrayRead(coordinates, &coords);
1020: MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1021: MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1022: PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1023: PetscDrawClear(draw);
1025: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1026: for (c = cStart; c < cEnd; ++c) {
1027: PetscScalar *coords = NULL;
1028: PetscInt numCoords,coneSize;
1030: DMPlexGetConeSize(dm, c, &coneSize);
1031: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1032: switch (coneSize) {
1033: case 3:
1034: PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1035: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1036: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1037: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1038: break;
1039: case 4:
1040: PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1041: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1042: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1043: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1044: PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1045: break;
1046: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1047: }
1048: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1049: }
1050: for (c = cStart; c < cEnd; ++c) {
1051: PetscScalar *coords = NULL;
1052: PetscInt numCoords,coneSize;
1054: DMPlexGetConeSize(dm, c, &coneSize);
1055: DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1056: switch (coneSize) {
1057: case 3:
1058: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1059: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1060: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1061: break;
1062: case 4:
1063: PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1064: PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1065: PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
1066: PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1067: break;
1068: default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1069: }
1070: DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1071: }
1072: PetscDrawFlush(draw);
1073: PetscDrawPause(draw);
1074: PetscDrawSave(draw);
1075: return(0);
1076: }
1078: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1079: {
1080: PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1081: PetscErrorCode ierr;
1086: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
1087: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
1088: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
1089: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
1090: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
1091: if (iascii) {
1092: PetscViewerFormat format;
1093: PetscViewerGetFormat(viewer, &format);
1094: if (format == PETSC_VIEWER_ASCII_GLVIS) {
1095: DMPlexView_GLVis(dm, viewer);
1096: } else {
1097: DMPlexView_Ascii(dm, viewer);
1098: }
1099: } else if (ishdf5) {
1100: #if defined(PETSC_HAVE_HDF5)
1101: DMPlexView_HDF5_Internal(dm, viewer);
1102: #else
1103: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1104: #endif
1105: } else if (isvtk) {
1106: DMPlexVTKWriteAll((PetscObject) dm,viewer);
1107: } else if (isdraw) {
1108: DMPlexView_Draw(dm, viewer);
1109: } else if (isglvis) {
1110: DMPlexView_GLVis(dm, viewer);
1111: } else {
1112: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1113: }
1114: /* Optionally view the partition */
1115: PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1116: if (flg) {
1117: Vec ranks;
1118: DMPlexCreateRankField(dm, &ranks);
1119: VecView(ranks, viewer);
1120: VecDestroy(&ranks);
1121: }
1122: return(0);
1123: }
1125: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1126: {
1127: PetscBool ishdf5;
1133: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
1134: if (ishdf5) {
1135: #if defined(PETSC_HAVE_HDF5)
1136: PetscViewerFormat format;
1137: PetscViewerGetFormat(viewer, &format);
1138: if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1139: DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1140: } else {
1141: DMPlexLoad_HDF5_Internal(dm, viewer);
1142: }
1143: #else
1144: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1145: #endif
1146: } else {
1147: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1148: }
1149: return(0);
1150: }
1152: PetscErrorCode DMDestroy_Plex(DM dm)
1153: {
1154: DM_Plex *mesh = (DM_Plex*) dm->data;
1158: PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1159: PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1160: if (--mesh->refct > 0) return(0);
1161: PetscSectionDestroy(&mesh->coneSection);
1162: PetscFree(mesh->cones);
1163: PetscFree(mesh->coneOrientations);
1164: PetscSectionDestroy(&mesh->supportSection);
1165: PetscSectionDestroy(&mesh->subdomainSection);
1166: PetscFree(mesh->supports);
1167: PetscFree(mesh->facesTmp);
1168: PetscFree(mesh->tetgenOpts);
1169: PetscFree(mesh->triangleOpts);
1170: PetscPartitionerDestroy(&mesh->partitioner);
1171: DMLabelDestroy(&mesh->subpointMap);
1172: ISDestroy(&mesh->globalVertexNumbers);
1173: ISDestroy(&mesh->globalCellNumbers);
1174: PetscSectionDestroy(&mesh->anchorSection);
1175: ISDestroy(&mesh->anchorIS);
1176: PetscSectionDestroy(&mesh->parentSection);
1177: PetscFree(mesh->parents);
1178: PetscFree(mesh->childIDs);
1179: PetscSectionDestroy(&mesh->childSection);
1180: PetscFree(mesh->children);
1181: DMDestroy(&mesh->referenceTree);
1182: PetscGridHashDestroy(&mesh->lbox);
1183: /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1184: PetscFree(mesh);
1185: return(0);
1186: }
1188: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1189: {
1190: PetscSection sectionGlobal;
1191: PetscInt bs = -1, mbs;
1192: PetscInt localSize;
1193: PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1194: PetscErrorCode ierr;
1195: MatType mtype;
1196: ISLocalToGlobalMapping ltog;
1199: MatInitializePackage();
1200: mtype = dm->mattype;
1201: DMGetGlobalSection(dm, §ionGlobal);
1202: /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1203: PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1204: MatCreate(PetscObjectComm((PetscObject)dm), J);
1205: MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1206: MatSetType(*J, mtype);
1207: MatSetFromOptions(*J);
1208: MatGetBlockSize(*J, &mbs);
1209: if (mbs > 1) bs = mbs;
1210: PetscStrcmp(mtype, MATSHELL, &isShell);
1211: PetscStrcmp(mtype, MATBAIJ, &isBlock);
1212: PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1213: PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1214: PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1215: PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1216: PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1217: PetscStrcmp(mtype, MATIS, &isMatIS);
1218: if (!isShell) {
1219: PetscSection subSection;
1220: PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1221: PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1222: PetscInt pStart, pEnd, p, dof, cdof;
1224: /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
1225: if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
1226: PetscSection section;
1227: PetscInt size;
1229: DMGetSection(dm, §ion);
1230: PetscSectionGetStorageSize(section, &size);
1231: PetscMalloc1(size,<ogidx);
1232: DMPlexGetSubdomainSection(dm, &subSection);
1233: } else {
1234: DMGetLocalToGlobalMapping(dm,<og);
1235: }
1236: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1237: for (p = pStart, lsize = 0; p < pEnd; ++p) {
1238: PetscInt bdof;
1240: PetscSectionGetDof(sectionGlobal, p, &dof);
1241: PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1242: dof = dof < 0 ? -(dof+1) : dof;
1243: bdof = cdof && (dof-cdof) ? 1 : dof;
1244: if (dof) {
1245: if (bs < 0) {bs = bdof;}
1246: else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1247: }
1248: if (isMatIS) {
1249: PetscInt loff,c,off;
1250: PetscSectionGetOffset(subSection, p, &loff);
1251: PetscSectionGetOffset(sectionGlobal, p, &off);
1252: for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1253: }
1254: }
1255: /* Must have same blocksize on all procs (some might have no points) */
1256: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1257: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1258: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1259: else {bs = bsMinMax[0];}
1260: bs = bs < 0 ? 1 : bs;
1261: if (isMatIS) {
1262: PetscInt l;
1263: /* Must reduce indices by blocksize */
1264: if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1265: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, <og);
1266: }
1267: MatSetLocalToGlobalMapping(*J,ltog,ltog);
1268: if (isMatIS) {
1269: ISLocalToGlobalMappingDestroy(<og);
1270: }
1271: PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1272: DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1273: PetscFree4(dnz, onz, dnzu, onzu);
1274: }
1275: MatSetDM(*J, dm);
1276: return(0);
1277: }
1279: /*@
1280: DMPlexGetSubdomainSection - Returns the section associated with the subdomain
1282: Not collective
1284: Input Parameter:
1285: . mesh - The DMPlex
1287: Output Parameters:
1288: . subsection - The subdomain section
1290: Level: developer
1292: .seealso:
1293: @*/
1294: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1295: {
1296: DM_Plex *mesh = (DM_Plex*) dm->data;
1301: if (!mesh->subdomainSection) {
1302: PetscSection section;
1303: PetscSF sf;
1305: PetscSFCreate(PETSC_COMM_SELF,&sf);
1306: DMGetSection(dm,§ion);
1307: PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1308: PetscSFDestroy(&sf);
1309: }
1310: *subsection = mesh->subdomainSection;
1311: return(0);
1312: }
1314: /*@
1315: DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1317: Not collective
1319: Input Parameter:
1320: . mesh - The DMPlex
1322: Output Parameters:
1323: + pStart - The first mesh point
1324: - pEnd - The upper bound for mesh points
1326: Level: beginner
1328: .seealso: DMPlexCreate(), DMPlexSetChart()
1329: @*/
1330: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1331: {
1332: DM_Plex *mesh = (DM_Plex*) dm->data;
1337: PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1338: return(0);
1339: }
1341: /*@
1342: DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1344: Not collective
1346: Input Parameters:
1347: + mesh - The DMPlex
1348: . pStart - The first mesh point
1349: - pEnd - The upper bound for mesh points
1351: Output Parameters:
1353: Level: beginner
1355: .seealso: DMPlexCreate(), DMPlexGetChart()
1356: @*/
1357: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1358: {
1359: DM_Plex *mesh = (DM_Plex*) dm->data;
1364: PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1365: PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1366: return(0);
1367: }
1369: /*@
1370: DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
1372: Not collective
1374: Input Parameters:
1375: + mesh - The DMPlex
1376: - p - The point, which must lie in the chart set with DMPlexSetChart()
1378: Output Parameter:
1379: . size - The cone size for point p
1381: Level: beginner
1383: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1384: @*/
1385: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1386: {
1387: DM_Plex *mesh = (DM_Plex*) dm->data;
1393: PetscSectionGetDof(mesh->coneSection, p, size);
1394: return(0);
1395: }
1397: /*@
1398: DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
1400: Not collective
1402: Input Parameters:
1403: + mesh - The DMPlex
1404: . p - The point, which must lie in the chart set with DMPlexSetChart()
1405: - size - The cone size for point p
1407: Output Parameter:
1409: Note:
1410: This should be called after DMPlexSetChart().
1412: Level: beginner
1414: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1415: @*/
1416: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1417: {
1418: DM_Plex *mesh = (DM_Plex*) dm->data;
1423: PetscSectionSetDof(mesh->coneSection, p, size);
1425: mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1426: return(0);
1427: }
1429: /*@
1430: DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
1432: Not collective
1434: Input Parameters:
1435: + mesh - The DMPlex
1436: . p - The point, which must lie in the chart set with DMPlexSetChart()
1437: - size - The additional cone size for point p
1439: Output Parameter:
1441: Note:
1442: This should be called after DMPlexSetChart().
1444: Level: beginner
1446: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1447: @*/
1448: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1449: {
1450: DM_Plex *mesh = (DM_Plex*) dm->data;
1451: PetscInt csize;
1456: PetscSectionAddDof(mesh->coneSection, p, size);
1457: PetscSectionGetDof(mesh->coneSection, p, &csize);
1459: mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1460: return(0);
1461: }
1463: /*@C
1464: DMPlexGetCone - Return the points on the in-edges for this point in the DAG
1466: Not collective
1468: Input Parameters:
1469: + mesh - The DMPlex
1470: - p - The point, which must lie in the chart set with DMPlexSetChart()
1472: Output Parameter:
1473: . cone - An array of points which are on the in-edges for point p
1475: Level: beginner
1477: Fortran Notes:
1478: Since it returns an array, this routine is only available in Fortran 90, and you must
1479: include petsc.h90 in your code.
1481: You must also call DMPlexRestoreCone() after you finish using the returned array.
1483: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1484: @*/
1485: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1486: {
1487: DM_Plex *mesh = (DM_Plex*) dm->data;
1488: PetscInt off;
1494: PetscSectionGetOffset(mesh->coneSection, p, &off);
1495: *cone = &mesh->cones[off];
1496: return(0);
1497: }
1499: /*@
1500: DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point
1502: Not collective
1504: Input Parameters:
1505: + mesh - The DMPlex
1506: . p - The point, which must lie in the chart set with DMPlexSetChart()
1507: - cone - An array of points which are on the in-edges for point p
1509: Output Parameter:
1511: Note:
1512: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1514: Developer Note: Why not call this DMPlexSetCover()
1516: Level: beginner
1518: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1519: @*/
1520: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1521: {
1522: DM_Plex *mesh = (DM_Plex*) dm->data;
1523: PetscInt pStart, pEnd;
1524: PetscInt dof, off, c;
1529: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1530: PetscSectionGetDof(mesh->coneSection, p, &dof);
1532: PetscSectionGetOffset(mesh->coneSection, p, &off);
1533: 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);
1534: for (c = 0; c < dof; ++c) {
1535: 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);
1536: mesh->cones[off+c] = cone[c];
1537: }
1538: return(0);
1539: }
1541: /*@C
1542: DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
1544: Not collective
1546: Input Parameters:
1547: + mesh - The DMPlex
1548: - p - The point, which must lie in the chart set with DMPlexSetChart()
1550: Output Parameter:
1551: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1552: integer giving the prescription for cone traversal. If it is negative, the cone is
1553: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1554: the index of the cone point on which to start.
1556: Level: beginner
1558: Fortran Notes:
1559: Since it returns an array, this routine is only available in Fortran 90, and you must
1560: include petsc.h90 in your code.
1562: You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1564: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1565: @*/
1566: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1567: {
1568: DM_Plex *mesh = (DM_Plex*) dm->data;
1569: PetscInt off;
1574: #if defined(PETSC_USE_DEBUG)
1575: {
1576: PetscInt dof;
1577: PetscSectionGetDof(mesh->coneSection, p, &dof);
1579: }
1580: #endif
1581: PetscSectionGetOffset(mesh->coneSection, p, &off);
1583: *coneOrientation = &mesh->coneOrientations[off];
1584: return(0);
1585: }
1587: /*@
1588: DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
1590: Not collective
1592: Input Parameters:
1593: + mesh - The DMPlex
1594: . p - The point, which must lie in the chart set with DMPlexSetChart()
1595: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1596: integer giving the prescription for cone traversal. If it is negative, the cone is
1597: traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1598: the index of the cone point on which to start.
1600: Output Parameter:
1602: Note:
1603: This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1605: Level: beginner
1607: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1608: @*/
1609: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1610: {
1611: DM_Plex *mesh = (DM_Plex*) dm->data;
1612: PetscInt pStart, pEnd;
1613: PetscInt dof, off, c;
1618: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1619: PetscSectionGetDof(mesh->coneSection, p, &dof);
1621: PetscSectionGetOffset(mesh->coneSection, p, &off);
1622: 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);
1623: for (c = 0; c < dof; ++c) {
1624: PetscInt cdof, o = coneOrientation[c];
1626: PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1627: 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);
1628: mesh->coneOrientations[off+c] = o;
1629: }
1630: return(0);
1631: }
1633: /*@
1634: DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
1636: Not collective
1638: Input Parameters:
1639: + mesh - The DMPlex
1640: . p - The point, which must lie in the chart set with DMPlexSetChart()
1641: . conePos - The local index in the cone where the point should be put
1642: - conePoint - The mesh point to insert
1644: Level: beginner
1646: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1647: @*/
1648: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1649: {
1650: DM_Plex *mesh = (DM_Plex*) dm->data;
1651: PetscInt pStart, pEnd;
1652: PetscInt dof, off;
1657: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1658: 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);
1659: 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);
1660: PetscSectionGetDof(mesh->coneSection, p, &dof);
1661: PetscSectionGetOffset(mesh->coneSection, p, &off);
1662: 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);
1663: mesh->cones[off+conePos] = conePoint;
1664: return(0);
1665: }
1667: /*@
1668: DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
1670: Not collective
1672: Input Parameters:
1673: + mesh - The DMPlex
1674: . p - The point, which must lie in the chart set with DMPlexSetChart()
1675: . conePos - The local index in the cone where the point should be put
1676: - coneOrientation - The point orientation to insert
1678: Level: beginner
1680: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1681: @*/
1682: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1683: {
1684: DM_Plex *mesh = (DM_Plex*) dm->data;
1685: PetscInt pStart, pEnd;
1686: PetscInt dof, off;
1691: PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1692: 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);
1693: PetscSectionGetDof(mesh->coneSection, p, &dof);
1694: PetscSectionGetOffset(mesh->coneSection, p, &off);
1695: 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);
1696: mesh->coneOrientations[off+conePos] = coneOrientation;
1697: return(0);
1698: }
1700: /*@
1701: DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
1703: Not collective
1705: Input Parameters:
1706: + mesh - The DMPlex
1707: - p - The point, which must lie in the chart set with DMPlexSetChart()
1709: Output Parameter:
1710: . size - The support size for point p
1712: Level: beginner
1714: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1715: @*/
1716: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1717: {
1718: DM_Plex *mesh = (DM_Plex*) dm->data;
1724: PetscSectionGetDof(mesh->supportSection, p, size);
1725: return(0);
1726: }
1728: /*@
1729: DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
1731: Not collective
1733: Input Parameters:
1734: + mesh - The DMPlex
1735: . p - The point, which must lie in the chart set with DMPlexSetChart()
1736: - size - The support size for point p
1738: Output Parameter:
1740: Note:
1741: This should be called after DMPlexSetChart().
1743: Level: beginner
1745: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1746: @*/
1747: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1748: {
1749: DM_Plex *mesh = (DM_Plex*) dm->data;
1754: PetscSectionSetDof(mesh->supportSection, p, size);
1756: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1757: return(0);
1758: }
1760: /*@C
1761: DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
1763: Not collective
1765: Input Parameters:
1766: + mesh - The DMPlex
1767: - p - The point, which must lie in the chart set with DMPlexSetChart()
1769: Output Parameter:
1770: . support - An array of points which are on the out-edges for point p
1772: Level: beginner
1774: Fortran Notes:
1775: Since it returns an array, this routine is only available in Fortran 90, and you must
1776: include petsc.h90 in your code.
1778: You must also call DMPlexRestoreSupport() after you finish using the returned array.
1780: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1781: @*/
1782: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1783: {
1784: DM_Plex *mesh = (DM_Plex*) dm->data;
1785: PetscInt off;
1791: PetscSectionGetOffset(mesh->supportSection, p, &off);
1792: *support = &mesh->supports[off];
1793: return(0);
1794: }
1796: /*@
1797: DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
1799: Not collective
1801: Input Parameters:
1802: + mesh - The DMPlex
1803: . p - The point, which must lie in the chart set with DMPlexSetChart()
1804: - support - An array of points which are on the out-edges for point p
1806: Output Parameter:
1808: Note:
1809: This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1811: Level: beginner
1813: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1814: @*/
1815: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1816: {
1817: DM_Plex *mesh = (DM_Plex*) dm->data;
1818: PetscInt pStart, pEnd;
1819: PetscInt dof, off, c;
1824: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1825: PetscSectionGetDof(mesh->supportSection, p, &dof);
1827: PetscSectionGetOffset(mesh->supportSection, p, &off);
1828: 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);
1829: for (c = 0; c < dof; ++c) {
1830: 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);
1831: mesh->supports[off+c] = support[c];
1832: }
1833: return(0);
1834: }
1836: /*@
1837: DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
1839: Not collective
1841: Input Parameters:
1842: + mesh - The DMPlex
1843: . p - The point, which must lie in the chart set with DMPlexSetChart()
1844: . supportPos - The local index in the cone where the point should be put
1845: - supportPoint - The mesh point to insert
1847: Level: beginner
1849: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1850: @*/
1851: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1852: {
1853: DM_Plex *mesh = (DM_Plex*) dm->data;
1854: PetscInt pStart, pEnd;
1855: PetscInt dof, off;
1860: PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1861: PetscSectionGetDof(mesh->supportSection, p, &dof);
1862: PetscSectionGetOffset(mesh->supportSection, p, &off);
1863: 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);
1864: 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);
1865: 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);
1866: mesh->supports[off+supportPos] = supportPoint;
1867: return(0);
1868: }
1870: /*@C
1871: DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
1873: Not collective
1875: Input Parameters:
1876: + mesh - The DMPlex
1877: . p - The point, which must lie in the chart set with DMPlexSetChart()
1878: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
1879: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1881: Output Parameters:
1882: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1883: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1885: Note:
1886: If using internal storage (points is NULL on input), each call overwrites the last output.
1888: Fortran Notes:
1889: Since it returns an array, this routine is only available in Fortran 90, and you must
1890: include petsc.h90 in your code.
1892: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1894: Level: beginner
1896: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1897: @*/
1898: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1899: {
1900: DM_Plex *mesh = (DM_Plex*) dm->data;
1901: PetscInt *closure, *fifo;
1902: const PetscInt *tmp = NULL, *tmpO = NULL;
1903: PetscInt tmpSize, t;
1904: PetscInt depth = 0, maxSize;
1905: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
1906: PetscErrorCode ierr;
1910: DMPlexGetDepth(dm, &depth);
1911: /* This is only 1-level */
1912: if (useCone) {
1913: DMPlexGetConeSize(dm, p, &tmpSize);
1914: DMPlexGetCone(dm, p, &tmp);
1915: DMPlexGetConeOrientation(dm, p, &tmpO);
1916: } else {
1917: DMPlexGetSupportSize(dm, p, &tmpSize);
1918: DMPlexGetSupport(dm, p, &tmp);
1919: }
1920: if (depth == 1) {
1921: if (*points) {
1922: closure = *points;
1923: } else {
1924: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1925: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1926: }
1927: closure[0] = p; closure[1] = 0;
1928: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1929: closure[closureSize] = tmp[t];
1930: closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1931: }
1932: if (numPoints) *numPoints = closureSize/2;
1933: if (points) *points = closure;
1934: return(0);
1935: }
1936: {
1937: PetscInt c, coneSeries, s,supportSeries;
1939: c = mesh->maxConeSize;
1940: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1941: s = mesh->maxSupportSize;
1942: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1943: maxSize = 2*PetscMax(coneSeries,supportSeries);
1944: }
1945: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
1946: if (*points) {
1947: closure = *points;
1948: } else {
1949: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1950: }
1951: closure[0] = p; closure[1] = 0;
1952: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1953: const PetscInt cp = tmp[t];
1954: const PetscInt co = tmpO ? tmpO[t] : 0;
1956: closure[closureSize] = cp;
1957: closure[closureSize+1] = co;
1958: fifo[fifoSize] = cp;
1959: fifo[fifoSize+1] = co;
1960: }
1961: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1962: while (fifoSize - fifoStart) {
1963: const PetscInt q = fifo[fifoStart];
1964: const PetscInt o = fifo[fifoStart+1];
1965: const PetscInt rev = o >= 0 ? 0 : 1;
1966: const PetscInt off = rev ? -(o+1) : o;
1968: if (useCone) {
1969: DMPlexGetConeSize(dm, q, &tmpSize);
1970: DMPlexGetCone(dm, q, &tmp);
1971: DMPlexGetConeOrientation(dm, q, &tmpO);
1972: } else {
1973: DMPlexGetSupportSize(dm, q, &tmpSize);
1974: DMPlexGetSupport(dm, q, &tmp);
1975: tmpO = NULL;
1976: }
1977: for (t = 0; t < tmpSize; ++t) {
1978: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
1979: const PetscInt cp = tmp[i];
1980: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1981: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1982: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1983: PetscInt co = tmpO ? tmpO[i] : 0;
1984: PetscInt c;
1986: if (rev) {
1987: PetscInt childSize, coff;
1988: DMPlexGetConeSize(dm, cp, &childSize);
1989: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1990: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1991: }
1992: /* Check for duplicate */
1993: for (c = 0; c < closureSize; c += 2) {
1994: if (closure[c] == cp) break;
1995: }
1996: if (c == closureSize) {
1997: closure[closureSize] = cp;
1998: closure[closureSize+1] = co;
1999: fifo[fifoSize] = cp;
2000: fifo[fifoSize+1] = co;
2001: closureSize += 2;
2002: fifoSize += 2;
2003: }
2004: }
2005: fifoStart += 2;
2006: }
2007: if (numPoints) *numPoints = closureSize/2;
2008: if (points) *points = closure;
2009: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2010: return(0);
2011: }
2013: /*@C
2014: 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
2016: Not collective
2018: Input Parameters:
2019: + mesh - The DMPlex
2020: . p - The point, which must lie in the chart set with DMPlexSetChart()
2021: . orientation - The orientation of the point
2022: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2023: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2025: Output Parameters:
2026: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2027: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2029: Note:
2030: If using internal storage (points is NULL on input), each call overwrites the last output.
2032: Fortran Notes:
2033: Since it returns an array, this routine is only available in Fortran 90, and you must
2034: include petsc.h90 in your code.
2036: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2038: Level: beginner
2040: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2041: @*/
2042: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2043: {
2044: DM_Plex *mesh = (DM_Plex*) dm->data;
2045: PetscInt *closure, *fifo;
2046: const PetscInt *tmp = NULL, *tmpO = NULL;
2047: PetscInt tmpSize, t;
2048: PetscInt depth = 0, maxSize;
2049: PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0;
2050: PetscErrorCode ierr;
2054: DMPlexGetDepth(dm, &depth);
2055: /* This is only 1-level */
2056: if (useCone) {
2057: DMPlexGetConeSize(dm, p, &tmpSize);
2058: DMPlexGetCone(dm, p, &tmp);
2059: DMPlexGetConeOrientation(dm, p, &tmpO);
2060: } else {
2061: DMPlexGetSupportSize(dm, p, &tmpSize);
2062: DMPlexGetSupport(dm, p, &tmp);
2063: }
2064: if (depth == 1) {
2065: if (*points) {
2066: closure = *points;
2067: } else {
2068: maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2069: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2070: }
2071: closure[0] = p; closure[1] = ornt;
2072: for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2073: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2074: closure[closureSize] = tmp[i];
2075: closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2076: }
2077: if (numPoints) *numPoints = closureSize/2;
2078: if (points) *points = closure;
2079: return(0);
2080: }
2081: {
2082: PetscInt c, coneSeries, s,supportSeries;
2084: c = mesh->maxConeSize;
2085: coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2086: s = mesh->maxSupportSize;
2087: supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2088: maxSize = 2*PetscMax(coneSeries,supportSeries);
2089: }
2090: DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2091: if (*points) {
2092: closure = *points;
2093: } else {
2094: DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2095: }
2096: closure[0] = p; closure[1] = ornt;
2097: for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2098: const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2099: const PetscInt cp = tmp[i];
2100: PetscInt co = tmpO ? tmpO[i] : 0;
2102: if (ornt < 0) {
2103: PetscInt childSize, coff;
2104: DMPlexGetConeSize(dm, cp, &childSize);
2105: coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2106: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2107: }
2108: closure[closureSize] = cp;
2109: closure[closureSize+1] = co;
2110: fifo[fifoSize] = cp;
2111: fifo[fifoSize+1] = co;
2112: }
2113: /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2114: while (fifoSize - fifoStart) {
2115: const PetscInt q = fifo[fifoStart];
2116: const PetscInt o = fifo[fifoStart+1];
2117: const PetscInt rev = o >= 0 ? 0 : 1;
2118: const PetscInt off = rev ? -(o+1) : o;
2120: if (useCone) {
2121: DMPlexGetConeSize(dm, q, &tmpSize);
2122: DMPlexGetCone(dm, q, &tmp);
2123: DMPlexGetConeOrientation(dm, q, &tmpO);
2124: } else {
2125: DMPlexGetSupportSize(dm, q, &tmpSize);
2126: DMPlexGetSupport(dm, q, &tmp);
2127: tmpO = NULL;
2128: }
2129: for (t = 0; t < tmpSize; ++t) {
2130: const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize;
2131: const PetscInt cp = tmp[i];
2132: /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2133: /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2134: const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2135: PetscInt co = tmpO ? tmpO[i] : 0;
2136: PetscInt c;
2138: if (rev) {
2139: PetscInt childSize, coff;
2140: DMPlexGetConeSize(dm, cp, &childSize);
2141: coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2142: co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2143: }
2144: /* Check for duplicate */
2145: for (c = 0; c < closureSize; c += 2) {
2146: if (closure[c] == cp) break;
2147: }
2148: if (c == closureSize) {
2149: closure[closureSize] = cp;
2150: closure[closureSize+1] = co;
2151: fifo[fifoSize] = cp;
2152: fifo[fifoSize+1] = co;
2153: closureSize += 2;
2154: fifoSize += 2;
2155: }
2156: }
2157: fifoStart += 2;
2158: }
2159: if (numPoints) *numPoints = closureSize/2;
2160: if (points) *points = closure;
2161: DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2162: return(0);
2163: }
2165: /*@C
2166: DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
2168: Not collective
2170: Input Parameters:
2171: + mesh - The DMPlex
2172: . p - The point, which must lie in the chart set with DMPlexSetChart()
2173: . useCone - PETSC_TRUE for in-edges, otherwise use out-edges
2174: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
2175: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
2177: Note:
2178: If not using internal storage (points is not NULL on input), this call is unnecessary
2180: Fortran Notes:
2181: Since it returns an array, this routine is only available in Fortran 90, and you must
2182: include petsc.h90 in your code.
2184: The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2186: Level: beginner
2188: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2189: @*/
2190: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2191: {
2198: DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2199: if (numPoints) *numPoints = 0;
2200: return(0);
2201: }
2203: /*@
2204: DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
2206: Not collective
2208: Input Parameter:
2209: . mesh - The DMPlex
2211: Output Parameters:
2212: + maxConeSize - The maximum number of in-edges
2213: - maxSupportSize - The maximum number of out-edges
2215: Level: beginner
2217: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2218: @*/
2219: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2220: {
2221: DM_Plex *mesh = (DM_Plex*) dm->data;
2225: if (maxConeSize) *maxConeSize = mesh->maxConeSize;
2226: if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2227: return(0);
2228: }
2230: PetscErrorCode DMSetUp_Plex(DM dm)
2231: {
2232: DM_Plex *mesh = (DM_Plex*) dm->data;
2233: PetscInt size;
2238: PetscSectionSetUp(mesh->coneSection);
2239: PetscSectionGetStorageSize(mesh->coneSection, &size);
2240: PetscMalloc1(size, &mesh->cones);
2241: PetscCalloc1(size, &mesh->coneOrientations);
2242: if (mesh->maxSupportSize) {
2243: PetscSectionSetUp(mesh->supportSection);
2244: PetscSectionGetStorageSize(mesh->supportSection, &size);
2245: PetscMalloc1(size, &mesh->supports);
2246: }
2247: return(0);
2248: }
2250: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2251: {
2255: if (subdm) {DMClone(dm, subdm);}
2256: DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2257: if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2258: if (dm->useNatural && dm->sfMigration) {
2259: PetscSF sfMigrationInv,sfNatural;
2260: PetscSection section, sectionSeq;
2262: (*subdm)->sfMigration = dm->sfMigration;
2263: PetscObjectReference((PetscObject) dm->sfMigration);
2264: DMGetSection((*subdm), §ion);
2265: PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2266: PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq);
2267: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2269: DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2270: (*subdm)->sfNatural = sfNatural;
2271: PetscSectionDestroy(§ionSeq);
2272: PetscSFDestroy(&sfMigrationInv);
2273: }
2274: return(0);
2275: }
2277: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2278: {
2280: PetscInt i = 0;
2283: if (superdm) {DMClone(dms[0], superdm);}
2284: DMCreateSuperDM_Section_Private(dms, len, is, superdm);
2285: (*superdm)->useNatural = PETSC_FALSE;
2286: for (i = 0; i < len; i++){
2287: if (dms[i]->useNatural && dms[i]->sfMigration) {
2288: PetscSF sfMigrationInv,sfNatural;
2289: PetscSection section, sectionSeq;
2291: (*superdm)->sfMigration = dms[i]->sfMigration;
2292: PetscObjectReference((PetscObject) dms[i]->sfMigration);
2293: (*superdm)->useNatural = PETSC_TRUE;
2294: DMGetSection((*superdm), §ion);
2295: PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2296: PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq);
2297: PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2299: DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2300: (*superdm)->sfNatural = sfNatural;
2301: PetscSectionDestroy(§ionSeq);
2302: PetscSFDestroy(&sfMigrationInv);
2303: break;
2304: }
2305: }
2306: return(0);
2307: }
2309: /*@
2310: DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
2312: Not collective
2314: Input Parameter:
2315: . mesh - The DMPlex
2317: Output Parameter:
2319: Note:
2320: This should be called after all calls to DMPlexSetCone()
2322: Level: beginner
2324: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2325: @*/
2326: PetscErrorCode DMPlexSymmetrize(DM dm)
2327: {
2328: DM_Plex *mesh = (DM_Plex*) dm->data;
2329: PetscInt *offsets;
2330: PetscInt supportSize;
2331: PetscInt pStart, pEnd, p;
2336: if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2337: /* Calculate support sizes */
2338: DMPlexGetChart(dm, &pStart, &pEnd);
2339: for (p = pStart; p < pEnd; ++p) {
2340: PetscInt dof, off, c;
2342: PetscSectionGetDof(mesh->coneSection, p, &dof);
2343: PetscSectionGetOffset(mesh->coneSection, p, &off);
2344: for (c = off; c < off+dof; ++c) {
2345: PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2346: }
2347: }
2348: for (p = pStart; p < pEnd; ++p) {
2349: PetscInt dof;
2351: PetscSectionGetDof(mesh->supportSection, p, &dof);
2353: mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2354: }
2355: PetscSectionSetUp(mesh->supportSection);
2356: /* Calculate supports */
2357: PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2358: PetscMalloc1(supportSize, &mesh->supports);
2359: PetscCalloc1(pEnd - pStart, &offsets);
2360: for (p = pStart; p < pEnd; ++p) {
2361: PetscInt dof, off, c;
2363: PetscSectionGetDof(mesh->coneSection, p, &dof);
2364: PetscSectionGetOffset(mesh->coneSection, p, &off);
2365: for (c = off; c < off+dof; ++c) {
2366: const PetscInt q = mesh->cones[c];
2367: PetscInt offS;
2369: PetscSectionGetOffset(mesh->supportSection, q, &offS);
2371: mesh->supports[offS+offsets[q]] = p;
2372: ++offsets[q];
2373: }
2374: }
2375: PetscFree(offsets);
2376: return(0);
2377: }
2379: static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt);
2381: /*@
2382: DMPlexStratify - The DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2383: can be illustrated by a Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2384: same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2385: the DAG.
2387: Collective on dm
2389: Input Parameter:
2390: . mesh - The DMPlex
2392: Output Parameter:
2394: Notes:
2395: Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2396: 1 for edges, and so on. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2397: manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed
2398: via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1.
2400: DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
2402: Level: beginner
2404: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2405: @*/
2406: PetscErrorCode DMPlexStratify(DM dm)
2407: {
2408: DM_Plex *mesh = (DM_Plex*) dm->data;
2409: DMLabel label;
2410: PetscInt pStart, pEnd, p;
2411: PetscInt numRoots = 0, numLeaves = 0;
2412: PetscInt cMax, fMax, eMax, vMax;
2417: PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2418: /* Calculate depth */
2419: DMPlexGetChart(dm, &pStart, &pEnd);
2420: DMCreateLabel(dm, "depth");
2421: DMPlexGetDepthLabel(dm, &label);
2422: /* Initialize roots and count leaves */
2423: for (p = pStart; p < pEnd; ++p) {
2424: PetscInt coneSize, supportSize;
2426: DMPlexGetConeSize(dm, p, &coneSize);
2427: DMPlexGetSupportSize(dm, p, &supportSize);
2428: if (!coneSize && supportSize) {
2429: ++numRoots;
2430: DMLabelSetValue(label, p, 0);
2431: } else if (!supportSize && coneSize) {
2432: ++numLeaves;
2433: } else if (!supportSize && !coneSize) {
2434: /* Isolated points */
2435: DMLabelSetValue(label, p, 0);
2436: }
2437: }
2438: if (numRoots + numLeaves == (pEnd - pStart)) {
2439: for (p = pStart; p < pEnd; ++p) {
2440: PetscInt coneSize, supportSize;
2442: DMPlexGetConeSize(dm, p, &coneSize);
2443: DMPlexGetSupportSize(dm, p, &supportSize);
2444: if (!supportSize && coneSize) {
2445: DMLabelSetValue(label, p, 1);
2446: }
2447: }
2448: } else {
2449: IS pointIS;
2450: PetscInt numPoints = 0, level = 0;
2452: DMLabelGetStratumIS(label, level, &pointIS);
2453: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2454: while (numPoints) {
2455: const PetscInt *points;
2456: const PetscInt newLevel = level+1;
2458: ISGetIndices(pointIS, &points);
2459: for (p = 0; p < numPoints; ++p) {
2460: const PetscInt point = points[p];
2461: const PetscInt *support;
2462: PetscInt supportSize, s;
2464: DMPlexGetSupportSize(dm, point, &supportSize);
2465: DMPlexGetSupport(dm, point, &support);
2466: for (s = 0; s < supportSize; ++s) {
2467: DMLabelSetValue(label, support[s], newLevel);
2468: }
2469: }
2470: ISRestoreIndices(pointIS, &points);
2471: ++level;
2472: ISDestroy(&pointIS);
2473: DMLabelGetStratumIS(label, level, &pointIS);
2474: if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2475: else {numPoints = 0;}
2476: }
2477: ISDestroy(&pointIS);
2478: }
2479: { /* just in case there is an empty process */
2480: PetscInt numValues, maxValues = 0, v;
2482: DMLabelGetNumValues(label,&numValues);
2483: for (v = 0; v < numValues; v++) {
2484: IS pointIS;
2486: DMLabelGetStratumIS(label, v, &pointIS);
2487: if (pointIS) {
2488: PetscInt min, max, numPoints;
2489: PetscInt start;
2490: PetscBool contig;
2492: ISGetLocalSize(pointIS, &numPoints);
2493: ISGetMinMax(pointIS, &min, &max);
2494: ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2495: if (start == 0 && contig) {
2496: ISDestroy(&pointIS);
2497: ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2498: DMLabelSetStratumIS(label, v, pointIS);
2499: }
2500: }
2501: ISDestroy(&pointIS);
2502: }
2503: MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2504: for (v = numValues; v < maxValues; v++) {
2505: DMLabelAddStratum(label,v);
2506: }
2507: }
2508: DMLabelGetState(label, &mesh->depthState);
2510: DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2511: if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2512: DMLabel dimLabel;
2513: PetscInt dim;
2515: DMGetDimension(dm, &dim);
2516: DMGetLabel(dm, "dim", &dimLabel);
2517: if (!dimLabel) {
2518: DMCreateLabel(dm, "dim");
2519: DMGetLabel(dm, "dim", &dimLabel);
2520: }
2521: if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2522: if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2523: if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2524: if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2525: }
2526: PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2527: return(0);
2528: }
2530: /*@C
2531: DMPlexGetJoin - Get an array for the join of the set of points
2533: Not Collective
2535: Input Parameters:
2536: + dm - The DMPlex object
2537: . numPoints - The number of input points for the join
2538: - points - The input points
2540: Output Parameters:
2541: + numCoveredPoints - The number of points in the join
2542: - coveredPoints - The points in the join
2544: Level: intermediate
2546: Note: Currently, this is restricted to a single level join
2548: Fortran Notes:
2549: Since it returns an array, this routine is only available in Fortran 90, and you must
2550: include petsc.h90 in your code.
2552: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2554: .keywords: mesh
2555: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2556: @*/
2557: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2558: {
2559: DM_Plex *mesh = (DM_Plex*) dm->data;
2560: PetscInt *join[2];
2561: PetscInt joinSize, i = 0;
2562: PetscInt dof, off, p, c, m;
2570: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2571: DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2572: /* Copy in support of first point */
2573: PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2574: PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2575: for (joinSize = 0; joinSize < dof; ++joinSize) {
2576: join[i][joinSize] = mesh->supports[off+joinSize];
2577: }
2578: /* Check each successive support */
2579: for (p = 1; p < numPoints; ++p) {
2580: PetscInt newJoinSize = 0;
2582: PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2583: PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2584: for (c = 0; c < dof; ++c) {
2585: const PetscInt point = mesh->supports[off+c];
2587: for (m = 0; m < joinSize; ++m) {
2588: if (point == join[i][m]) {
2589: join[1-i][newJoinSize++] = point;
2590: break;
2591: }
2592: }
2593: }
2594: joinSize = newJoinSize;
2595: i = 1-i;
2596: }
2597: *numCoveredPoints = joinSize;
2598: *coveredPoints = join[i];
2599: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2600: return(0);
2601: }
2603: /*@C
2604: DMPlexRestoreJoin - Restore an array for the join of the set of points
2606: Not Collective
2608: Input Parameters:
2609: + dm - The DMPlex object
2610: . numPoints - The number of input points for the join
2611: - points - The input points
2613: Output Parameters:
2614: + numCoveredPoints - The number of points in the join
2615: - coveredPoints - The points in the join
2617: Fortran Notes:
2618: Since it returns an array, this routine is only available in Fortran 90, and you must
2619: include petsc.h90 in your code.
2621: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2623: Level: intermediate
2625: .keywords: mesh
2626: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2627: @*/
2628: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2629: {
2637: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2638: if (numCoveredPoints) *numCoveredPoints = 0;
2639: return(0);
2640: }
2642: /*@C
2643: DMPlexGetFullJoin - Get an array for the join of the set of points
2645: Not Collective
2647: Input Parameters:
2648: + dm - The DMPlex object
2649: . numPoints - The number of input points for the join
2650: - points - The input points
2652: Output Parameters:
2653: + numCoveredPoints - The number of points in the join
2654: - coveredPoints - The points in the join
2656: Fortran Notes:
2657: Since it returns an array, this routine is only available in Fortran 90, and you must
2658: include petsc.h90 in your code.
2660: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2662: Level: intermediate
2664: .keywords: mesh
2665: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2666: @*/
2667: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2668: {
2669: DM_Plex *mesh = (DM_Plex*) dm->data;
2670: PetscInt *offsets, **closures;
2671: PetscInt *join[2];
2672: PetscInt depth = 0, maxSize, joinSize = 0, i = 0;
2673: PetscInt p, d, c, m, ms;
2682: DMPlexGetDepth(dm, &depth);
2683: PetscCalloc1(numPoints, &closures);
2684: DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2685: ms = mesh->maxSupportSize;
2686: maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2687: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2688: DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);
2690: for (p = 0; p < numPoints; ++p) {
2691: PetscInt closureSize;
2693: DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);
2695: offsets[p*(depth+2)+0] = 0;
2696: for (d = 0; d < depth+1; ++d) {
2697: PetscInt pStart, pEnd, i;
2699: DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2700: for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2701: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2702: offsets[p*(depth+2)+d+1] = i;
2703: break;
2704: }
2705: }
2706: if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2707: }
2708: 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);
2709: }
2710: for (d = 0; d < depth+1; ++d) {
2711: PetscInt dof;
2713: /* Copy in support of first point */
2714: dof = offsets[d+1] - offsets[d];
2715: for (joinSize = 0; joinSize < dof; ++joinSize) {
2716: join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2717: }
2718: /* Check each successive cone */
2719: for (p = 1; p < numPoints && joinSize; ++p) {
2720: PetscInt newJoinSize = 0;
2722: dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2723: for (c = 0; c < dof; ++c) {
2724: const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2726: for (m = 0; m < joinSize; ++m) {
2727: if (point == join[i][m]) {
2728: join[1-i][newJoinSize++] = point;
2729: break;
2730: }
2731: }
2732: }
2733: joinSize = newJoinSize;
2734: i = 1-i;
2735: }
2736: if (joinSize) break;
2737: }
2738: *numCoveredPoints = joinSize;
2739: *coveredPoints = join[i];
2740: for (p = 0; p < numPoints; ++p) {
2741: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2742: }
2743: PetscFree(closures);
2744: DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2745: DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2746: return(0);
2747: }
2749: /*@C
2750: DMPlexGetMeet - Get an array for the meet of the set of points
2752: Not Collective
2754: Input Parameters:
2755: + dm - The DMPlex object
2756: . numPoints - The number of input points for the meet
2757: - points - The input points
2759: Output Parameters:
2760: + numCoveredPoints - The number of points in the meet
2761: - coveredPoints - The points in the meet
2763: Level: intermediate
2765: Note: Currently, this is restricted to a single level meet
2767: Fortran Notes:
2768: Since it returns an array, this routine is only available in Fortran 90, and you must
2769: include petsc.h90 in your code.
2771: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2773: .keywords: mesh
2774: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2775: @*/
2776: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2777: {
2778: DM_Plex *mesh = (DM_Plex*) dm->data;
2779: PetscInt *meet[2];
2780: PetscInt meetSize, i = 0;
2781: PetscInt dof, off, p, c, m;
2789: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2790: DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2791: /* Copy in cone of first point */
2792: PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2793: PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2794: for (meetSize = 0; meetSize < dof; ++meetSize) {
2795: meet[i][meetSize] = mesh->cones[off+meetSize];
2796: }
2797: /* Check each successive cone */
2798: for (p = 1; p < numPoints; ++p) {
2799: PetscInt newMeetSize = 0;
2801: PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2802: PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2803: for (c = 0; c < dof; ++c) {
2804: const PetscInt point = mesh->cones[off+c];
2806: for (m = 0; m < meetSize; ++m) {
2807: if (point == meet[i][m]) {
2808: meet[1-i][newMeetSize++] = point;
2809: break;
2810: }
2811: }
2812: }
2813: meetSize = newMeetSize;
2814: i = 1-i;
2815: }
2816: *numCoveringPoints = meetSize;
2817: *coveringPoints = meet[i];
2818: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2819: return(0);
2820: }
2822: /*@C
2823: DMPlexRestoreMeet - Restore an array for the meet of the set of points
2825: Not Collective
2827: Input Parameters:
2828: + dm - The DMPlex object
2829: . numPoints - The number of input points for the meet
2830: - points - The input points
2832: Output Parameters:
2833: + numCoveredPoints - The number of points in the meet
2834: - coveredPoints - The points in the meet
2836: Level: intermediate
2838: Fortran Notes:
2839: Since it returns an array, this routine is only available in Fortran 90, and you must
2840: include petsc.h90 in your code.
2842: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2844: .keywords: mesh
2845: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2846: @*/
2847: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2848: {
2856: DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2857: if (numCoveredPoints) *numCoveredPoints = 0;
2858: return(0);
2859: }
2861: /*@C
2862: DMPlexGetFullMeet - Get an array for the meet of the set of points
2864: Not Collective
2866: Input Parameters:
2867: + dm - The DMPlex object
2868: . numPoints - The number of input points for the meet
2869: - points - The input points
2871: Output Parameters:
2872: + numCoveredPoints - The number of points in the meet
2873: - coveredPoints - The points in the meet
2875: Level: intermediate
2877: Fortran Notes:
2878: Since it returns an array, this routine is only available in Fortran 90, and you must
2879: include petsc.h90 in your code.
2881: The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2883: .keywords: mesh
2884: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2885: @*/
2886: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2887: {
2888: DM_Plex *mesh = (DM_Plex*) dm->data;
2889: PetscInt *offsets, **closures;
2890: PetscInt *meet[2];
2891: PetscInt height = 0, maxSize, meetSize = 0, i = 0;
2892: PetscInt p, h, c, m, mc;
2901: DMPlexGetDepth(dm, &height);
2902: PetscMalloc1(numPoints, &closures);
2903: DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2904: mc = mesh->maxConeSize;
2905: maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2906: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
2907: DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);
2909: for (p = 0; p < numPoints; ++p) {
2910: PetscInt closureSize;
2912: DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);
2914: offsets[p*(height+2)+0] = 0;
2915: for (h = 0; h < height+1; ++h) {
2916: PetscInt pStart, pEnd, i;
2918: DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2919: for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2920: if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2921: offsets[p*(height+2)+h+1] = i;
2922: break;
2923: }
2924: }
2925: if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2926: }
2927: 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);
2928: }
2929: for (h = 0; h < height+1; ++h) {
2930: PetscInt dof;
2932: /* Copy in cone of first point */
2933: dof = offsets[h+1] - offsets[h];
2934: for (meetSize = 0; meetSize < dof; ++meetSize) {
2935: meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2936: }
2937: /* Check each successive cone */
2938: for (p = 1; p < numPoints && meetSize; ++p) {
2939: PetscInt newMeetSize = 0;
2941: dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2942: for (c = 0; c < dof; ++c) {
2943: const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2945: for (m = 0; m < meetSize; ++m) {
2946: if (point == meet[i][m]) {
2947: meet[1-i][newMeetSize++] = point;
2948: break;
2949: }
2950: }
2951: }
2952: meetSize = newMeetSize;
2953: i = 1-i;
2954: }
2955: if (meetSize) break;
2956: }
2957: *numCoveredPoints = meetSize;
2958: *coveredPoints = meet[i];
2959: for (p = 0; p < numPoints; ++p) {
2960: DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2961: }
2962: PetscFree(closures);
2963: DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2964: DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2965: return(0);
2966: }
2968: /*@C
2969: DMPlexEqual - Determine if two DMs have the same topology
2971: Not Collective
2973: Input Parameters:
2974: + dmA - A DMPlex object
2975: - dmB - A DMPlex object
2977: Output Parameters:
2978: . equal - PETSC_TRUE if the topologies are identical
2980: Level: intermediate
2982: Notes:
2983: We are not solving graph isomorphism, so we do not permutation.
2985: .keywords: mesh
2986: .seealso: DMPlexGetCone()
2987: @*/
2988: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2989: {
2990: PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;
2998: *equal = PETSC_FALSE;
2999: DMPlexGetDepth(dmA, &depth);
3000: DMPlexGetDepth(dmB, &depthB);
3001: if (depth != depthB) return(0);
3002: DMPlexGetChart(dmA, &pStart, &pEnd);
3003: DMPlexGetChart(dmB, &pStartB, &pEndB);
3004: if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3005: for (p = pStart; p < pEnd; ++p) {
3006: const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3007: PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s;
3009: DMPlexGetConeSize(dmA, p, &coneSize);
3010: DMPlexGetCone(dmA, p, &cone);
3011: DMPlexGetConeOrientation(dmA, p, &ornt);
3012: DMPlexGetConeSize(dmB, p, &coneSizeB);
3013: DMPlexGetCone(dmB, p, &coneB);
3014: DMPlexGetConeOrientation(dmB, p, &orntB);
3015: if (coneSize != coneSizeB) return(0);
3016: for (c = 0; c < coneSize; ++c) {
3017: if (cone[c] != coneB[c]) return(0);
3018: if (ornt[c] != orntB[c]) return(0);
3019: }
3020: DMPlexGetSupportSize(dmA, p, &supportSize);
3021: DMPlexGetSupport(dmA, p, &support);
3022: DMPlexGetSupportSize(dmB, p, &supportSizeB);
3023: DMPlexGetSupport(dmB, p, &supportB);
3024: if (supportSize != supportSizeB) return(0);
3025: for (s = 0; s < supportSize; ++s) {
3026: if (support[s] != supportB[s]) return(0);
3027: }
3028: }
3029: *equal = PETSC_TRUE;
3030: return(0);
3031: }
3033: /*@C
3034: DMPlexGetNumFaceVertices - Returns the number of vertices on a face
3036: Not Collective
3038: Input Parameters:
3039: + dm - The DMPlex
3040: . cellDim - The cell dimension
3041: - numCorners - The number of vertices on a cell
3043: Output Parameters:
3044: . numFaceVertices - The number of vertices on a face
3046: Level: developer
3048: Notes:
3049: Of course this can only work for a restricted set of symmetric shapes
3051: .seealso: DMPlexGetCone()
3052: @*/
3053: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3054: {
3055: MPI_Comm comm;
3059: PetscObjectGetComm((PetscObject)dm,&comm);
3061: switch (cellDim) {
3062: case 0:
3063: *numFaceVertices = 0;
3064: break;
3065: case 1:
3066: *numFaceVertices = 1;
3067: break;
3068: case 2:
3069: switch (numCorners) {
3070: case 3: /* triangle */
3071: *numFaceVertices = 2; /* Edge has 2 vertices */
3072: break;
3073: case 4: /* quadrilateral */
3074: *numFaceVertices = 2; /* Edge has 2 vertices */
3075: break;
3076: case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3077: *numFaceVertices = 3; /* Edge has 3 vertices */
3078: break;
3079: case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3080: *numFaceVertices = 3; /* Edge has 3 vertices */
3081: break;
3082: default:
3083: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3084: }
3085: break;
3086: case 3:
3087: switch (numCorners) {
3088: case 4: /* tetradehdron */
3089: *numFaceVertices = 3; /* Face has 3 vertices */
3090: break;
3091: case 6: /* tet cohesive cells */
3092: *numFaceVertices = 4; /* Face has 4 vertices */
3093: break;
3094: case 8: /* hexahedron */
3095: *numFaceVertices = 4; /* Face has 4 vertices */
3096: break;
3097: case 9: /* tet cohesive Lagrange cells */
3098: *numFaceVertices = 6; /* Face has 6 vertices */
3099: break;
3100: case 10: /* quadratic tetrahedron */
3101: *numFaceVertices = 6; /* Face has 6 vertices */
3102: break;
3103: case 12: /* hex cohesive Lagrange cells */
3104: *numFaceVertices = 6; /* Face has 6 vertices */
3105: break;
3106: case 18: /* quadratic tet cohesive Lagrange cells */
3107: *numFaceVertices = 6; /* Face has 6 vertices */
3108: break;
3109: case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3110: *numFaceVertices = 9; /* Face has 9 vertices */
3111: break;
3112: default:
3113: SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3114: }
3115: break;
3116: default:
3117: SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3118: }
3119: return(0);
3120: }
3122: /*@
3123: DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
3125: Not Collective
3127: Input Parameter:
3128: . dm - The DMPlex object
3130: Output Parameter:
3131: . depthLabel - The DMLabel recording point depth
3133: Level: developer
3135: .keywords: mesh, points
3136: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3137: @*/
3138: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3139: {
3145: if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3146: *depthLabel = dm->depthLabel;
3147: return(0);
3148: }
3150: /*@
3151: DMPlexGetDepth - Get the depth of the DAG representing this mesh
3153: Not Collective
3155: Input Parameter:
3156: . dm - The DMPlex object
3158: Output Parameter:
3159: . depth - The number of strata (breadth first levels) in the DAG
3161: Level: developer
3163: .keywords: mesh, points
3164: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3165: @*/
3166: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3167: {
3168: DMLabel label;
3169: PetscInt d = 0;
3175: DMPlexGetDepthLabel(dm, &label);
3176: if (label) {DMLabelGetNumValues(label, &d);}
3177: *depth = d-1;
3178: return(0);
3179: }
3181: /*@
3182: DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
3184: Not Collective
3186: Input Parameters:
3187: + dm - The DMPlex object
3188: - stratumValue - The requested depth
3190: Output Parameters:
3191: + start - The first point at this depth
3192: - end - One beyond the last point at this depth
3194: Level: developer
3196: .keywords: mesh, points
3197: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3198: @*/
3199: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3200: {
3201: DMLabel label;
3202: PetscInt pStart, pEnd;
3209: DMPlexGetChart(dm, &pStart, &pEnd);
3210: if (pStart == pEnd) return(0);
3211: if (stratumValue < 0) {
3212: if (start) *start = pStart;
3213: if (end) *end = pEnd;
3214: return(0);
3215: }
3216: DMPlexGetDepthLabel(dm, &label);
3217: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3218: DMLabelGetStratumBounds(label, stratumValue, start, end);
3219: return(0);
3220: }
3222: /*@
3223: DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3225: Not Collective
3227: Input Parameters:
3228: + dm - The DMPlex object
3229: - stratumValue - The requested height
3231: Output Parameters:
3232: + start - The first point at this height
3233: - end - One beyond the last point at this height
3235: Level: developer
3237: .keywords: mesh, points
3238: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3239: @*/
3240: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3241: {
3242: DMLabel label;
3243: PetscInt depth, pStart, pEnd;
3250: DMPlexGetChart(dm, &pStart, &pEnd);
3251: if (pStart == pEnd) return(0);
3252: if (stratumValue < 0) {
3253: if (start) *start = pStart;
3254: if (end) *end = pEnd;
3255: return(0);
3256: }
3257: DMPlexGetDepthLabel(dm, &label);
3258: if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3259: DMLabelGetNumValues(label, &depth);
3260: DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3261: return(0);
3262: }
3264: /* Set the number of dof on each point and separate by fields */
3265: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3266: {
3267: PetscInt *pMax;
3268: PetscInt depth, cellHeight, pStart = 0, pEnd = 0;
3269: PetscInt Nf, p, d, dep, f;
3270: PetscBool *isFE;
3274: PetscMalloc1(numFields, &isFE);
3275: DMGetNumFields(dm, &Nf);
3276: for (f = 0; f < numFields; ++f) {
3277: PetscObject obj;
3278: PetscClassId id;
3280: isFE[f] = PETSC_FALSE;
3281: if (f >= Nf) continue;
3282: DMGetField(dm, f, &obj);
3283: PetscObjectGetClassId(obj, &id);
3284: if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;}
3285: else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3286: }
3287: PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
3288: if (numFields > 0) {
3289: PetscSectionSetNumFields(*section, numFields);
3290: if (numComp) {
3291: for (f = 0; f < numFields; ++f) {
3292: PetscSectionSetFieldComponents(*section, f, numComp[f]);
3293: if (isFE[f]) {
3294: PetscFE fe;
3295: PetscDualSpace dspace;
3296: const PetscInt ***perms;
3297: const PetscScalar ***flips;
3298: const PetscInt *numDof;
3300: DMGetField(dm,f,(PetscObject *) &fe);
3301: PetscFEGetDualSpace(fe,&dspace);
3302: PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3303: PetscDualSpaceGetNumDof(dspace,&numDof);
3304: if (perms || flips) {
3305: DM K;
3306: DMLabel depthLabel;
3307: PetscInt depth, h;
3308: PetscSectionSym sym;
3310: PetscDualSpaceGetDM(dspace,&K);
3311: DMPlexGetDepthLabel(dm,&depthLabel);
3312: DMPlexGetDepth(dm,&depth);
3313: PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
3314: for (h = 0; h <= depth; h++) {
3315: PetscDualSpace hspace;
3316: PetscInt kStart, kEnd;
3317: PetscInt kConeSize;
3318: const PetscInt **perms0 = NULL;
3319: const PetscScalar **flips0 = NULL;
3321: PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3322: DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3323: if (!hspace) continue;
3324: PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3325: if (perms) perms0 = perms[0];
3326: if (flips) flips0 = flips[0];
3327: if (!(perms0 || flips0)) continue;
3328: DMPlexGetConeSize(K,kStart,&kConeSize);
3329: PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3330: }
3331: PetscSectionSetFieldSym(*section,f,sym);
3332: PetscSectionSymDestroy(&sym);
3333: }
3334: }
3335: }
3336: }
3337: }
3338: DMPlexGetChart(dm, &pStart, &pEnd);
3339: PetscSectionSetChart(*section, pStart, pEnd);
3340: DMPlexGetDepth(dm, &depth);
3341: PetscMalloc1(depth+1,&pMax);
3342: DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3343: DMPlexGetVTKCellHeight(dm, &cellHeight);
3344: for (dep = 0; dep <= depth - cellHeight; ++dep) {
3345: d = dim == depth ? dep : (!dep ? 0 : dim);
3346: DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3347: pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3348: for (p = pStart; p < pEnd; ++p) {
3349: PetscInt tot = 0;
3351: for (f = 0; f < numFields; ++f) {
3352: if (isFE[f] && p >= pMax[dep]) continue;
3353: PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3354: tot += numDof[f*(dim+1)+d];
3355: }
3356: PetscSectionSetDof(*section, p, tot);
3357: }
3358: }
3359: PetscFree(pMax);
3360: PetscFree(isFE);
3361: return(0);
3362: }
3364: /* Set the number of dof on each point and separate by fields
3365: If bcComps is NULL or the IS is NULL, constrain every dof on the point
3366: */
3367: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3368: {
3369: PetscInt numFields;
3370: PetscInt bc;
3371: PetscSection aSec;
3375: PetscSectionGetNumFields(section, &numFields);
3376: for (bc = 0; bc < numBC; ++bc) {
3377: PetscInt field = 0;
3378: const PetscInt *comp;
3379: const PetscInt *idx;
3380: PetscInt Nc = -1, n, i;
3382: if (numFields) field = bcField[bc];
3383: if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3384: if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3385: ISGetLocalSize(bcPoints[bc], &n);
3386: ISGetIndices(bcPoints[bc], &idx);
3387: for (i = 0; i < n; ++i) {
3388: const PetscInt p = idx[i];
3389: PetscInt numConst;
3391: if (numFields) {
3392: PetscSectionGetFieldDof(section, p, field, &numConst);
3393: } else {
3394: PetscSectionGetDof(section, p, &numConst);
3395: }
3396: /* If Nc < 0, constrain every dof on the point */
3397: if (Nc > 0) numConst = PetscMin(numConst, Nc);
3398: if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3399: PetscSectionAddConstraintDof(section, p, numConst);
3400: }
3401: ISRestoreIndices(bcPoints[bc], &idx);
3402: if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3403: }
3404: DMPlexGetAnchors(dm, &aSec, NULL);
3405: if (aSec) {
3406: PetscInt aStart, aEnd, a;
3408: PetscSectionGetChart(aSec, &aStart, &aEnd);
3409: for (a = aStart; a < aEnd; a++) {
3410: PetscInt dof, f;
3412: PetscSectionGetDof(aSec, a, &dof);
3413: if (dof) {
3414: /* if there are point-to-point constraints, then all dofs are constrained */
3415: PetscSectionGetDof(section, a, &dof);
3416: PetscSectionSetConstraintDof(section, a, dof);
3417: for (f = 0; f < numFields; f++) {
3418: PetscSectionGetFieldDof(section, a, f, &dof);
3419: PetscSectionSetFieldConstraintDof(section, a, f, dof);
3420: }
3421: }
3422: }
3423: }
3424: return(0);
3425: }
3427: /* Set the constrained field indices on each point
3428: If bcComps is NULL or the IS is NULL, constrain every dof on the point
3429: */
3430: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3431: {
3432: PetscSection aSec;
3433: PetscInt *indices;
3434: PetscInt numFields, cdof, maxDof = 0, pStart, pEnd, p, bc, f, d;
3438: PetscSectionGetNumFields(section, &numFields);
3439: if (!numFields) return(0);
3440: /* Initialize all field indices to -1 */
3441: PetscSectionGetChart(section, &pStart, &pEnd);
3442: for (p = pStart; p < pEnd; ++p) {PetscSectionGetConstraintDof(section, p, &cdof); maxDof = PetscMax(maxDof, cdof);}
3443: PetscMalloc1(maxDof, &indices);
3444: for (d = 0; d < maxDof; ++d) indices[d] = -1;
3445: for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3446: /* Handle BC constraints */
3447: for (bc = 0; bc < numBC; ++bc) {
3448: const PetscInt field = bcField[bc];
3449: const PetscInt *comp, *idx;
3450: PetscInt Nc = -1, n, i;
3452: if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3453: if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3454: ISGetLocalSize(bcPoints[bc], &n);
3455: ISGetIndices(bcPoints[bc], &idx);
3456: for (i = 0; i < n; ++i) {
3457: const PetscInt p = idx[i];
3458: const PetscInt *find;
3459: PetscInt fdof, fcdof, c;
3461: PetscSectionGetFieldDof(section, p, field, &fdof);
3462: if (!fdof) continue;
3463: if (Nc < 0) {
3464: for (d = 0; d < fdof; ++d) indices[d] = d;
3465: fcdof = fdof;
3466: } else {
3467: PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3468: PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3469: for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3470: for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
3471: PetscSortRemoveDupsInt(&d, indices);
3472: for (c = d; c < fcdof; ++c) indices[c] = -1;
3473: fcdof = d;
3474: }
3475: PetscSectionSetFieldConstraintDof(section, p, field, fcdof);
3476: PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3477: }
3478: if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3479: ISRestoreIndices(bcPoints[bc], &idx);
3480: }
3481: /* Handle anchors */
3482: DMPlexGetAnchors(dm, &aSec, NULL);
3483: if (aSec) {
3484: PetscInt aStart, aEnd, a;
3486: for (d = 0; d < maxDof; ++d) indices[d] = d;
3487: PetscSectionGetChart(aSec, &aStart, &aEnd);
3488: for (a = aStart; a < aEnd; a++) {
3489: PetscInt dof, f;
3491: PetscSectionGetDof(aSec, a, &dof);
3492: if (dof) {
3493: /* if there are point-to-point constraints, then all dofs are constrained */
3494: for (f = 0; f < numFields; f++) {
3495: PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3496: }
3497: }
3498: }
3499: }
3500: PetscFree(indices);
3501: return(0);
3502: }
3504: /* Set the constrained indices on each point */
3505: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3506: {
3507: PetscInt *indices;
3508: PetscInt numFields, maxDof, pStart, pEnd, p, f, d;
3512: PetscSectionGetNumFields(section, &numFields);
3513: PetscSectionGetMaxDof(section, &maxDof);
3514: PetscSectionGetChart(section, &pStart, &pEnd);
3515: PetscMalloc1(maxDof, &indices);
3516: for (d = 0; d < maxDof; ++d) indices[d] = -1;
3517: for (p = pStart; p < pEnd; ++p) {
3518: PetscInt cdof, d;
3520: PetscSectionGetConstraintDof(section, p, &cdof);
3521: if (cdof) {
3522: if (numFields) {
3523: PetscInt numConst = 0, foff = 0;
3525: for (f = 0; f < numFields; ++f) {
3526: const PetscInt *find;
3527: PetscInt fcdof, fdof;
3529: PetscSectionGetFieldDof(section, p, f, &fdof);
3530: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3531: /* Change constraint numbering from field component to local dof number */
3532: PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3533: for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3534: numConst += fcdof;
3535: foff += fdof;
3536: }
3537: if (cdof != numConst) {PetscSectionSetConstraintDof(section, p, numConst);}
3538: } else {
3539: for (d = 0; d < cdof; ++d) indices[d] = d;
3540: }
3541: PetscSectionSetConstraintIndices(section, p, indices);
3542: }
3543: }
3544: PetscFree(indices);
3545: return(0);
3546: }
3548: /*@C
3549: DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
3551: Not Collective
3553: Input Parameters:
3554: + dm - The DMPlex object
3555: . dim - The spatial dimension of the problem
3556: . numFields - The number of fields in the problem
3557: . numComp - An array of size numFields that holds the number of components for each field
3558: . numDof - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3559: . numBC - The number of boundary conditions
3560: . bcField - An array of size numBC giving the field number for each boundry condition
3561: . bcComps - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3562: . bcPoints - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3563: - perm - Optional permutation of the chart, or NULL
3565: Output Parameter:
3566: . section - The PetscSection object
3568: Notes:
3569: numDof[f*(dim+1)+d] gives the number of dof for field f on points of dimension d. For instance, numDof[1] is the
3570: number of dof for field 0 on each edge.
3572: The chart permutation is the same one set using PetscSectionSetPermutation()
3574: Level: developer
3576: Fortran Notes:
3577: A Fortran 90 version is available as DMPlexCreateSectionF90()
3579: .keywords: mesh, elements
3580: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3581: @*/
3582: 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)
3583: {
3584: PetscSection aSec;
3588: DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3589: DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3590: if (perm) {PetscSectionSetPermutation(*section, perm);}
3591: PetscSectionSetUp(*section);
3592: DMPlexGetAnchors(dm,&aSec,NULL);
3593: if (numBC || aSec) {
3594: DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3595: DMPlexCreateSectionBCIndices(dm, *section);
3596: }
3597: PetscSectionViewFromOptions(*section,NULL,"-section_view");
3598: return(0);
3599: }
3601: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3602: {
3603: PetscSection section, s;
3604: Mat m;
3605: PetscInt maxHeight;
3609: DMClone(dm, cdm);
3610: DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3611: DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3612: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
3613: DMSetSection(*cdm, section);
3614: PetscSectionDestroy(§ion);
3615: PetscSectionCreate(PETSC_COMM_SELF, &s);
3616: MatCreate(PETSC_COMM_SELF, &m);
3617: DMSetDefaultConstraints(*cdm, s, m);
3618: PetscSectionDestroy(&s);
3619: MatDestroy(&m);
3620: return(0);
3621: }
3623: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3624: {
3625: Vec coordsLocal;
3626: DM coordsDM;
3630: *field = NULL;
3631: DMGetCoordinatesLocal(dm,&coordsLocal);
3632: DMGetCoordinateDM(dm,&coordsDM);
3633: if (coordsLocal && coordsDM) {
3634: DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3635: }
3636: return(0);
3637: }
3639: /*@C
3640: DMPlexGetConeSection - Return a section which describes the layout of cone data
3642: Not Collective
3644: Input Parameters:
3645: . dm - The DMPlex object
3647: Output Parameter:
3648: . section - The PetscSection object
3650: Level: developer
3652: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3653: @*/
3654: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3655: {
3656: DM_Plex *mesh = (DM_Plex*) dm->data;
3660: if (section) *section = mesh->coneSection;
3661: return(0);
3662: }
3664: /*@C
3665: DMPlexGetSupportSection - Return a section which describes the layout of support data
3667: Not Collective
3669: Input Parameters:
3670: . dm - The DMPlex object
3672: Output Parameter:
3673: . section - The PetscSection object
3675: Level: developer
3677: .seealso: DMPlexGetConeSection()
3678: @*/
3679: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3680: {
3681: DM_Plex *mesh = (DM_Plex*) dm->data;
3685: if (section) *section = mesh->supportSection;
3686: return(0);
3687: }
3689: /*@C
3690: DMPlexGetCones - Return cone data
3692: Not Collective
3694: Input Parameters:
3695: . dm - The DMPlex object
3697: Output Parameter:
3698: . cones - The cone for each point
3700: Level: developer
3702: .seealso: DMPlexGetConeSection()
3703: @*/
3704: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3705: {
3706: DM_Plex *mesh = (DM_Plex*) dm->data;
3710: if (cones) *cones = mesh->cones;
3711: return(0);
3712: }
3714: /*@C
3715: DMPlexGetConeOrientations - Return cone orientation data
3717: Not Collective
3719: Input Parameters:
3720: . dm - The DMPlex object
3722: Output Parameter:
3723: . coneOrientations - The cone orientation for each point
3725: Level: developer
3727: .seealso: DMPlexGetConeSection()
3728: @*/
3729: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3730: {
3731: DM_Plex *mesh = (DM_Plex*) dm->data;
3735: if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3736: return(0);
3737: }
3739: /******************************** FEM Support **********************************/
3741: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3742: {
3743: DMLabel label;
3744: PetscInt *perm;
3745: PetscInt dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3749: if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3750: DMGetDimension(dm, &dim);
3751: DMPlexGetDepthLabel(dm, &label);
3752: DMLabelGetValue(label, point, &depth);
3753: if (depth == 1) {eStart = point;}
3754: else if (depth == dim) {
3755: const PetscInt *cone;
3757: DMPlexGetCone(dm, point, &cone);
3758: eStart = cone[0];
3759: } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering", point, depth);
3760: if (!section) {DMGetSection(dm, §ion);}
3761: PetscSectionGetNumFields(section, &Nf);
3762: if (dim <= 1) return(0);
3763: for (f = 0; f < Nf; ++f) {
3764: /* An order k SEM disc has k-1 dofs on an edge */
3765: PetscSectionGetFieldDof(section, eStart, f, &k);
3766: PetscSectionGetFieldComponents(section, f, &Nc);
3767: k = k/Nc + 1;
3768: size += PetscPowInt(k+1, dim)*Nc;
3769: }
3770: PetscMalloc1(size, &perm);
3771: for (f = 0; f < Nf; ++f) {
3772: switch (dim) {
3773: case 2:
3774: /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3775: PetscSectionGetFieldDof(section, eStart, f, &k);
3776: PetscSectionGetFieldComponents(section, f, &Nc);
3777: k = k/Nc + 1;
3778: /* The SEM order is
3780: v_lb, {e_b}, v_rb,
3781: e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3782: v_lt, reverse {e_t}, v_rt
3783: */
3784: {
3785: const PetscInt of = 0;
3786: const PetscInt oeb = of + PetscSqr(k-1);
3787: const PetscInt oer = oeb + (k-1);
3788: const PetscInt oet = oer + (k-1);
3789: const PetscInt oel = oet + (k-1);
3790: const PetscInt ovlb = oel + (k-1);
3791: const PetscInt ovrb = ovlb + 1;
3792: const PetscInt ovrt = ovrb + 1;
3793: const PetscInt ovlt = ovrt + 1;
3794: PetscInt o;
3796: /* bottom */
3797: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3798: for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3799: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3800: /* middle */
3801: for (i = 0; i < k-1; ++i) {
3802: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3803: 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;
3804: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3805: }
3806: /* top */
3807: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3808: for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3809: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3810: foffset = offset;
3811: }
3812: break;
3813: case 3:
3814: /* The original hex closure is
3816: {c,
3817: f_b, f_t, f_f, f_b, f_r, f_l,
3818: e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb,
3819: v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3820: */
3821: PetscSectionGetFieldDof(section, eStart, f, &k);
3822: PetscSectionGetFieldComponents(section, f, &Nc);
3823: k = k/Nc + 1;
3824: /* The SEM order is
3825: Bottom Slice
3826: v_blf, {e^{(k-1)-n}_bf}, v_brf,
3827: e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3828: v_blb, {e_bb}, v_brb,
3830: Middle Slice (j)
3831: {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3832: f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3833: e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3835: Top Slice
3836: v_tlf, {e_tf}, v_trf,
3837: e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3838: v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3839: */
3840: {
3841: const PetscInt oc = 0;
3842: const PetscInt ofb = oc + PetscSqr(k-1)*(k-1);
3843: const PetscInt oft = ofb + PetscSqr(k-1);
3844: const PetscInt off = oft + PetscSqr(k-1);
3845: const PetscInt ofk = off + PetscSqr(k-1);
3846: const PetscInt ofr = ofk + PetscSqr(k-1);
3847: const PetscInt ofl = ofr + PetscSqr(k-1);
3848: const PetscInt oebl = ofl + PetscSqr(k-1);
3849: const PetscInt oebb = oebl + (k-1);
3850: const PetscInt oebr = oebb + (k-1);
3851: const PetscInt oebf = oebr + (k-1);
3852: const PetscInt oetf = oebf + (k-1);
3853: const PetscInt oetr = oetf + (k-1);
3854: const PetscInt oetb = oetr + (k-1);
3855: const PetscInt oetl = oetb + (k-1);
3856: const PetscInt oerf = oetl + (k-1);
3857: const PetscInt oelf = oerf + (k-1);
3858: const PetscInt oelb = oelf + (k-1);
3859: const PetscInt oerb = oelb + (k-1);
3860: const PetscInt ovblf = oerb + (k-1);
3861: const PetscInt ovblb = ovblf + 1;
3862: const PetscInt ovbrb = ovblb + 1;
3863: const PetscInt ovbrf = ovbrb + 1;
3864: const PetscInt ovtlf = ovbrf + 1;
3865: const PetscInt ovtrf = ovtlf + 1;
3866: const PetscInt ovtrb = ovtrf + 1;
3867: const PetscInt ovtlb = ovtrb + 1;
3868: PetscInt o, n;
3870: /* Bottom Slice */
3871: /* bottom */
3872: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3873: for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3874: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3875: /* middle */
3876: for (i = 0; i < k-1; ++i) {
3877: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3878: 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;}
3879: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3880: }
3881: /* top */
3882: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3883: for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3884: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
3886: /* Middle Slice */
3887: for (j = 0; j < k-1; ++j) {
3888: /* bottom */
3889: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3890: 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;
3891: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3892: /* middle */
3893: for (i = 0; i < k-1; ++i) {
3894: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3895: 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;
3896: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3897: }
3898: /* top */
3899: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3900: 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;
3901: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3902: }
3904: /* Top Slice */
3905: /* bottom */
3906: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3907: for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3908: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3909: /* middle */
3910: for (i = 0; i < k-1; ++i) {
3911: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3912: for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3913: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3914: }
3915: /* top */
3916: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3917: for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3918: for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
3920: foffset = offset;
3921: }
3922: break;
3923: default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3924: }
3925: }
3926: if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3927: /* Check permutation */
3928: {
3929: PetscInt *check;
3931: PetscMalloc1(size, &check);
3932: 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]);}
3933: for (i = 0; i < size; ++i) check[perm[i]] = i;
3934: for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3935: PetscFree(check);
3936: }
3937: PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3938: return(0);
3939: }
3941: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3942: {
3943: PetscDS prob;
3944: PetscInt depth, Nf, h;
3945: DMLabel label;
3949: prob = dm->prob;
3950: Nf = prob->Nf;
3951: label = dm->depthLabel;
3952: *dspace = NULL;
3953: if (field < Nf) {
3954: PetscObject disc = prob->disc[field];
3956: if (disc->classid == PETSCFE_CLASSID) {
3957: PetscDualSpace dsp;
3959: PetscFEGetDualSpace((PetscFE)disc,&dsp);
3960: DMLabelGetNumValues(label,&depth);
3961: DMLabelGetValue(label,point,&h);
3962: h = depth - 1 - h;
3963: if (h) {
3964: PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3965: } else {
3966: *dspace = dsp;
3967: }
3968: }
3969: }
3970: return(0);
3971: }
3974: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3975: {
3976: PetscScalar *array, *vArray;
3977: const PetscInt *cone, *coneO;
3978: PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0;
3979: PetscErrorCode ierr;
3982: PetscSectionGetChart(section, &pStart, &pEnd);
3983: DMPlexGetConeSize(dm, point, &numPoints);
3984: DMPlexGetCone(dm, point, &cone);
3985: DMPlexGetConeOrientation(dm, point, &coneO);
3986: if (!values || !*values) {
3987: if ((point >= pStart) && (point < pEnd)) {
3988: PetscInt dof;
3990: PetscSectionGetDof(section, point, &dof);
3991: size += dof;
3992: }
3993: for (p = 0; p < numPoints; ++p) {
3994: const PetscInt cp = cone[p];
3995: PetscInt dof;
3997: if ((cp < pStart) || (cp >= pEnd)) continue;
3998: PetscSectionGetDof(section, cp, &dof);
3999: size += dof;
4000: }
4001: if (!values) {
4002: if (csize) *csize = size;
4003: return(0);
4004: }
4005: DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
4006: } else {
4007: array = *values;
4008: }
4009: size = 0;
4010: VecGetArray(v, &vArray);
4011: if ((point >= pStart) && (point < pEnd)) {
4012: PetscInt dof, off, d;
4013: PetscScalar *varr;
4015: PetscSectionGetDof(section, point, &dof);
4016: PetscSectionGetOffset(section, point, &off);
4017: varr = &vArray[off];
4018: for (d = 0; d < dof; ++d, ++offset) {
4019: array[offset] = varr[d];
4020: }
4021: size += dof;
4022: }
4023: for (p = 0; p < numPoints; ++p) {
4024: const PetscInt cp = cone[p];
4025: PetscInt o = coneO[p];
4026: PetscInt dof, off, d;
4027: PetscScalar *varr;
4029: if ((cp < pStart) || (cp >= pEnd)) continue;
4030: PetscSectionGetDof(section, cp, &dof);
4031: PetscSectionGetOffset(section, cp, &off);
4032: varr = &vArray[off];
4033: if (o >= 0) {
4034: for (d = 0; d < dof; ++d, ++offset) {
4035: array[offset] = varr[d];
4036: }
4037: } else {
4038: for (d = dof-1; d >= 0; --d, ++offset) {
4039: array[offset] = varr[d];
4040: }
4041: }
4042: size += dof;
4043: }
4044: VecRestoreArray(v, &vArray);
4045: if (!*values) {
4046: if (csize) *csize = size;
4047: *values = array;
4048: } else {
4049: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4050: *csize = size;
4051: }
4052: return(0);
4053: }
4055: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4056: {
4057: const PetscInt *cla;
4058: PetscInt np, *pts = NULL;
4062: PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
4063: if (!*clPoints) {
4064: PetscInt pStart, pEnd, p, q;
4066: PetscSectionGetChart(section, &pStart, &pEnd);
4067: DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
4068: /* Compress out points not in the section */
4069: for (p = 0, q = 0; p < np; p++) {
4070: PetscInt r = pts[2*p];
4071: if ((r >= pStart) && (r < pEnd)) {
4072: pts[q*2] = r;
4073: pts[q*2+1] = pts[2*p+1];
4074: ++q;
4075: }
4076: }
4077: np = q;
4078: cla = NULL;
4079: } else {
4080: PetscInt dof, off;
4082: PetscSectionGetDof(*clSec, point, &dof);
4083: PetscSectionGetOffset(*clSec, point, &off);
4084: ISGetIndices(*clPoints, &cla);
4085: np = dof/2;
4086: pts = (PetscInt *) &cla[off];
4087: }
4088: *numPoints = np;
4089: *points = pts;
4090: *clp = cla;
4092: return(0);
4093: }
4095: static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4096: {
4100: if (!*clPoints) {
4101: DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
4102: } else {
4103: ISRestoreIndices(*clPoints, clp);
4104: }
4105: *numPoints = 0;
4106: *points = NULL;
4107: *clSec = NULL;
4108: *clPoints = NULL;
4109: *clp = NULL;
4110: return(0);
4111: }
4113: 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[])
4114: {
4115: PetscInt offset = 0, p;
4116: const PetscInt **perms = NULL;
4117: const PetscScalar **flips = NULL;
4118: PetscErrorCode ierr;
4121: *size = 0;
4122: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4123: for (p = 0; p < numPoints; p++) {
4124: const PetscInt point = points[2*p];
4125: const PetscInt *perm = perms ? perms[p] : NULL;
4126: const PetscScalar *flip = flips ? flips[p] : NULL;
4127: PetscInt dof, off, d;
4128: const PetscScalar *varr;
4130: PetscSectionGetDof(section, point, &dof);
4131: PetscSectionGetOffset(section, point, &off);
4132: varr = &vArray[off];
4133: if (clperm) {
4134: if (perm) {
4135: for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
4136: } else {
4137: for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d];
4138: }
4139: if (flip) {
4140: for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d];
4141: }
4142: } else {
4143: if (perm) {
4144: for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
4145: } else {
4146: for (d = 0; d < dof; d++) array[offset + d ] = varr[d];
4147: }
4148: if (flip) {
4149: for (d = 0; d < dof; d++) array[offset + d ] *= flip[d];
4150: }
4151: }
4152: offset += dof;
4153: }
4154: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4155: *size = offset;
4156: return(0);
4157: }
4159: 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[])
4160: {
4161: PetscInt offset = 0, f;
4162: PetscErrorCode ierr;
4165: *size = 0;
4166: for (f = 0; f < numFields; ++f) {
4167: PetscInt p;
4168: const PetscInt **perms = NULL;
4169: const PetscScalar **flips = NULL;
4171: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4172: for (p = 0; p < numPoints; p++) {
4173: const PetscInt point = points[2*p];
4174: PetscInt fdof, foff, b;
4175: const PetscScalar *varr;
4176: const PetscInt *perm = perms ? perms[p] : NULL;
4177: const PetscScalar *flip = flips ? flips[p] : NULL;
4179: PetscSectionGetFieldDof(section, point, f, &fdof);
4180: PetscSectionGetFieldOffset(section, point, f, &foff);
4181: varr = &vArray[foff];
4182: if (clperm) {
4183: if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}}
4184: else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}}
4185: if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}}
4186: } else {
4187: if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}}
4188: else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}}
4189: if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}}
4190: }
4191: offset += fdof;
4192: }
4193: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4194: }
4195: *size = offset;
4196: return(0);
4197: }
4199: /*@C
4200: DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4202: Not collective
4204: Input Parameters:
4205: + dm - The DM
4206: . section - The section describing the layout in v, or NULL to use the default section
4207: . v - The local vector
4208: . point - The point in the DM
4209: . csize - The size of the input values array, or NULL
4210: - values - An array to use for the values, or NULL to have it allocated automatically
4212: Output Parameters:
4213: + csize - The number of values in the closure
4214: - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4216: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4217: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4218: $ assembly function, and a user may already have allocated storage for this operation.
4219: $
4220: $ A typical use could be
4221: $
4222: $ values = NULL;
4223: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4224: $ for (cl = 0; cl < clSize; ++cl) {
4225: $ <Compute on closure>
4226: $ }
4227: $ DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4228: $
4229: $ or
4230: $
4231: $ PetscMalloc1(clMaxSize, &values);
4232: $ for (p = pStart; p < pEnd; ++p) {
4233: $ clSize = clMaxSize;
4234: $ DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4235: $ for (cl = 0; cl < clSize; ++cl) {
4236: $ <Compute on closure>
4237: $ }
4238: $ }
4239: $ PetscFree(values);
4241: Fortran Notes:
4242: Since it returns an array, this routine is only available in Fortran 90, and you must
4243: include petsc.h90 in your code.
4245: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4247: Level: intermediate
4249: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4250: @*/
4251: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4252: {
4253: PetscSection clSection;
4254: IS clPoints;
4255: PetscScalar *array;
4256: const PetscScalar *vArray;
4257: PetscInt *points = NULL;
4258: const PetscInt *clp, *perm;
4259: PetscInt depth, numFields, numPoints, size;
4260: PetscErrorCode ierr;
4264: if (!section) {DMGetSection(dm, §ion);}
4267: DMPlexGetDepth(dm, &depth);
4268: PetscSectionGetNumFields(section, &numFields);
4269: if (depth == 1 && numFields < 2) {
4270: DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4271: return(0);
4272: }
4273: /* Get points */
4274: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4275: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4276: /* Get array */
4277: if (!values || !*values) {
4278: PetscInt asize = 0, dof, p;
4280: for (p = 0; p < numPoints*2; p += 2) {
4281: PetscSectionGetDof(section, points[p], &dof);
4282: asize += dof;
4283: }
4284: if (!values) {
4285: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4286: if (csize) *csize = asize;
4287: return(0);
4288: }
4289: DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4290: } else {
4291: array = *values;
4292: }
4293: VecGetArrayRead(v, &vArray);
4294: /* Get values */
4295: if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4296: else {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4297: /* Cleanup points */
4298: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4299: /* Cleanup array */
4300: VecRestoreArrayRead(v, &vArray);
4301: if (!*values) {
4302: if (csize) *csize = size;
4303: *values = array;
4304: } else {
4305: if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4306: *csize = size;
4307: }
4308: return(0);
4309: }
4311: /*@C
4312: DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4314: Not collective
4316: Input Parameters:
4317: + dm - The DM
4318: . section - The section describing the layout in v, or NULL to use the default section
4319: . v - The local vector
4320: . point - The point in the DM
4321: . csize - The number of values in the closure, or NULL
4322: - values - The array of values, which is a borrowed array and should not be freed
4324: Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4326: Fortran Notes:
4327: Since it returns an array, this routine is only available in Fortran 90, and you must
4328: include petsc.h90 in your code.
4330: The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4332: Level: intermediate
4334: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4335: @*/
4336: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4337: {
4338: PetscInt size = 0;
4342: /* Should work without recalculating size */
4343: DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4344: *values = NULL;
4345: return(0);
4346: }
4348: PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;}
4349: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;}
4351: 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[])
4352: {
4353: PetscInt cdof; /* The number of constraints on this point */
4354: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4355: PetscScalar *a;
4356: PetscInt off, cind = 0, k;
4357: PetscErrorCode ierr;
4360: PetscSectionGetConstraintDof(section, point, &cdof);
4361: PetscSectionGetOffset(section, point, &off);
4362: a = &array[off];
4363: if (!cdof || setBC) {
4364: if (clperm) {
4365: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4366: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}}
4367: } else {
4368: if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4369: else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}}
4370: }
4371: } else {
4372: PetscSectionGetConstraintIndices(section, point, &cdofs);
4373: if (clperm) {
4374: if (perm) {for (k = 0; k < dof; ++k) {
4375: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4376: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4377: }
4378: } else {
4379: for (k = 0; k < dof; ++k) {
4380: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4381: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4382: }
4383: }
4384: } else {
4385: if (perm) {
4386: for (k = 0; k < dof; ++k) {
4387: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4388: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4389: }
4390: } else {
4391: for (k = 0; k < dof; ++k) {
4392: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4393: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4394: }
4395: }
4396: }
4397: }
4398: return(0);
4399: }
4401: 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[])
4402: {
4403: PetscInt cdof; /* The number of constraints on this point */
4404: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4405: PetscScalar *a;
4406: PetscInt off, cind = 0, k;
4407: PetscErrorCode ierr;
4410: PetscSectionGetConstraintDof(section, point, &cdof);
4411: PetscSectionGetOffset(section, point, &off);
4412: a = &array[off];
4413: if (cdof) {
4414: PetscSectionGetConstraintIndices(section, point, &cdofs);
4415: if (clperm) {
4416: if (perm) {
4417: for (k = 0; k < dof; ++k) {
4418: if ((cind < cdof) && (k == cdofs[cind])) {
4419: fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4420: cind++;
4421: }
4422: }
4423: } else {
4424: for (k = 0; k < dof; ++k) {
4425: if ((cind < cdof) && (k == cdofs[cind])) {
4426: fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));
4427: cind++;
4428: }
4429: }
4430: }
4431: } else {
4432: if (perm) {
4433: for (k = 0; k < dof; ++k) {
4434: if ((cind < cdof) && (k == cdofs[cind])) {
4435: fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4436: cind++;
4437: }
4438: }
4439: } else {
4440: for (k = 0; k < dof; ++k) {
4441: if ((cind < cdof) && (k == cdofs[cind])) {
4442: fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));
4443: cind++;
4444: }
4445: }
4446: }
4447: }
4448: }
4449: return(0);
4450: }
4452: 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[])
4453: {
4454: PetscScalar *a;
4455: PetscInt fdof, foff, fcdof, foffset = *offset;
4456: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4457: PetscInt cind = 0, b;
4458: PetscErrorCode ierr;
4461: PetscSectionGetFieldDof(section, point, f, &fdof);
4462: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4463: PetscSectionGetFieldOffset(section, point, f, &foff);
4464: a = &array[foff];
4465: if (!fcdof || setBC) {
4466: if (clperm) {
4467: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4468: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}}
4469: } else {
4470: if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4471: else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}}
4472: }
4473: } else {
4474: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4475: if (clperm) {
4476: if (perm) {
4477: for (b = 0; b < fdof; b++) {
4478: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4479: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4480: }
4481: } else {
4482: for (b = 0; b < fdof; b++) {
4483: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4484: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4485: }
4486: }
4487: } else {
4488: if (perm) {
4489: for (b = 0; b < fdof; b++) {
4490: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4491: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4492: }
4493: } else {
4494: for (b = 0; b < fdof; b++) {
4495: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4496: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4497: }
4498: }
4499: }
4500: }
4501: *offset += fdof;
4502: return(0);
4503: }
4505: 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[])
4506: {
4507: PetscScalar *a;
4508: PetscInt fdof, foff, fcdof, foffset = *offset;
4509: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4510: PetscInt cind = 0, ncind = 0, b;
4511: PetscBool ncSet, fcSet;
4512: PetscErrorCode ierr;
4515: PetscSectionGetFieldDof(section, point, f, &fdof);
4516: PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4517: PetscSectionGetFieldOffset(section, point, f, &foff);
4518: a = &array[foff];
4519: if (fcdof) {
4520: /* We just override fcdof and fcdofs with Ncc and comps */
4521: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4522: if (clperm) {
4523: if (perm) {
4524: if (comps) {
4525: for (b = 0; b < fdof; b++) {
4526: ncSet = fcSet = PETSC_FALSE;
4527: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4528: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4529: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4530: }
4531: } else {
4532: for (b = 0; b < fdof; b++) {
4533: if ((cind < fcdof) && (b == fcdofs[cind])) {
4534: fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4535: ++cind;
4536: }
4537: }
4538: }
4539: } else {
4540: if (comps) {
4541: for (b = 0; b < fdof; b++) {
4542: ncSet = fcSet = PETSC_FALSE;
4543: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4544: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4545: if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}
4546: }
4547: } else {
4548: for (b = 0; b < fdof; b++) {
4549: if ((cind < fcdof) && (b == fcdofs[cind])) {
4550: fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));
4551: ++cind;
4552: }
4553: }
4554: }
4555: }
4556: } else {
4557: if (perm) {
4558: if (comps) {
4559: for (b = 0; b < fdof; b++) {
4560: ncSet = fcSet = PETSC_FALSE;
4561: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4562: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4563: if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4564: }
4565: } else {
4566: for (b = 0; b < fdof; b++) {
4567: if ((cind < fcdof) && (b == fcdofs[cind])) {
4568: fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4569: ++cind;
4570: }
4571: }
4572: }
4573: } else {
4574: if (comps) {
4575: for (b = 0; b < fdof; b++) {
4576: ncSet = fcSet = PETSC_FALSE;
4577: if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4578: if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;}
4579: if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}
4580: }
4581: } else {
4582: for (b = 0; b < fdof; b++) {
4583: if ((cind < fcdof) && (b == fcdofs[cind])) {
4584: fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));
4585: ++cind;
4586: }
4587: }
4588: }
4589: }
4590: }
4591: }
4592: *offset += fdof;
4593: return(0);
4594: }
4596: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4597: {
4598: PetscScalar *array;
4599: const PetscInt *cone, *coneO;
4600: PetscInt pStart, pEnd, p, numPoints, off, dof;
4601: PetscErrorCode ierr;
4604: PetscSectionGetChart(section, &pStart, &pEnd);
4605: DMPlexGetConeSize(dm, point, &numPoints);
4606: DMPlexGetCone(dm, point, &cone);
4607: DMPlexGetConeOrientation(dm, point, &coneO);
4608: VecGetArray(v, &array);
4609: for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4610: const PetscInt cp = !p ? point : cone[p-1];
4611: const PetscInt o = !p ? 0 : coneO[p-1];
4613: if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4614: PetscSectionGetDof(section, cp, &dof);
4615: /* ADD_VALUES */
4616: {
4617: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4618: PetscScalar *a;
4619: PetscInt cdof, coff, cind = 0, k;
4621: PetscSectionGetConstraintDof(section, cp, &cdof);
4622: PetscSectionGetOffset(section, cp, &coff);
4623: a = &array[coff];
4624: if (!cdof) {
4625: if (o >= 0) {
4626: for (k = 0; k < dof; ++k) {
4627: a[k] += values[off+k];
4628: }
4629: } else {
4630: for (k = 0; k < dof; ++k) {
4631: a[k] += values[off+dof-k-1];
4632: }
4633: }
4634: } else {
4635: PetscSectionGetConstraintIndices(section, cp, &cdofs);
4636: if (o >= 0) {
4637: for (k = 0; k < dof; ++k) {
4638: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4639: a[k] += values[off+k];
4640: }
4641: } else {
4642: for (k = 0; k < dof; ++k) {
4643: if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4644: a[k] += values[off+dof-k-1];
4645: }
4646: }
4647: }
4648: }
4649: }
4650: VecRestoreArray(v, &array);
4651: return(0);
4652: }
4654: /*@C
4655: DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4657: Not collective
4659: Input Parameters:
4660: + dm - The DM
4661: . section - The section describing the layout in v, or NULL to use the default section
4662: . v - The local vector
4663: . point - The point in the DM
4664: . values - The array of values
4665: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4666: where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
4668: Fortran Notes:
4669: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4671: Level: intermediate
4673: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4674: @*/
4675: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4676: {
4677: PetscSection clSection;
4678: IS clPoints;
4679: PetscScalar *array;
4680: PetscInt *points = NULL;
4681: const PetscInt *clp, *clperm;
4682: PetscInt depth, numFields, numPoints, p;
4683: PetscErrorCode ierr;
4687: if (!section) {DMGetSection(dm, §ion);}
4690: DMPlexGetDepth(dm, &depth);
4691: PetscSectionGetNumFields(section, &numFields);
4692: if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4693: DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4694: return(0);
4695: }
4696: /* Get points */
4697: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4698: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4699: /* Get array */
4700: VecGetArray(v, &array);
4701: /* Get values */
4702: if (numFields > 0) {
4703: PetscInt offset = 0, f;
4704: for (f = 0; f < numFields; ++f) {
4705: const PetscInt **perms = NULL;
4706: const PetscScalar **flips = NULL;
4708: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4709: switch (mode) {
4710: case INSERT_VALUES:
4711: for (p = 0; p < numPoints; p++) {
4712: const PetscInt point = points[2*p];
4713: const PetscInt *perm = perms ? perms[p] : NULL;
4714: const PetscScalar *flip = flips ? flips[p] : NULL;
4715: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4716: } break;
4717: case INSERT_ALL_VALUES:
4718: for (p = 0; p < numPoints; p++) {
4719: const PetscInt point = points[2*p];
4720: const PetscInt *perm = perms ? perms[p] : NULL;
4721: const PetscScalar *flip = flips ? flips[p] : NULL;
4722: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4723: } break;
4724: case INSERT_BC_VALUES:
4725: for (p = 0; p < numPoints; p++) {
4726: const PetscInt point = points[2*p];
4727: const PetscInt *perm = perms ? perms[p] : NULL;
4728: const PetscScalar *flip = flips ? flips[p] : NULL;
4729: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4730: } break;
4731: case ADD_VALUES:
4732: for (p = 0; p < numPoints; p++) {
4733: const PetscInt point = points[2*p];
4734: const PetscInt *perm = perms ? perms[p] : NULL;
4735: const PetscScalar *flip = flips ? flips[p] : NULL;
4736: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4737: } break;
4738: case ADD_ALL_VALUES:
4739: for (p = 0; p < numPoints; p++) {
4740: const PetscInt point = points[2*p];
4741: const PetscInt *perm = perms ? perms[p] : NULL;
4742: const PetscScalar *flip = flips ? flips[p] : NULL;
4743: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4744: } break;
4745: case ADD_BC_VALUES:
4746: for (p = 0; p < numPoints; p++) {
4747: const PetscInt point = points[2*p];
4748: const PetscInt *perm = perms ? perms[p] : NULL;
4749: const PetscScalar *flip = flips ? flips[p] : NULL;
4750: updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4751: } break;
4752: default:
4753: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4754: }
4755: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4756: }
4757: } else {
4758: PetscInt dof, off;
4759: const PetscInt **perms = NULL;
4760: const PetscScalar **flips = NULL;
4762: PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4763: switch (mode) {
4764: case INSERT_VALUES:
4765: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4766: const PetscInt point = points[2*p];
4767: const PetscInt *perm = perms ? perms[p] : NULL;
4768: const PetscScalar *flip = flips ? flips[p] : NULL;
4769: PetscSectionGetDof(section, point, &dof);
4770: updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4771: } break;
4772: case INSERT_ALL_VALUES:
4773: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4774: const PetscInt point = points[2*p];
4775: const PetscInt *perm = perms ? perms[p] : NULL;
4776: const PetscScalar *flip = flips ? flips[p] : NULL;
4777: PetscSectionGetDof(section, point, &dof);
4778: updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array);
4779: } break;
4780: case INSERT_BC_VALUES:
4781: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4782: const PetscInt point = points[2*p];
4783: const PetscInt *perm = perms ? perms[p] : NULL;
4784: const PetscScalar *flip = flips ? flips[p] : NULL;
4785: PetscSectionGetDof(section, point, &dof);
4786: updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array);
4787: } break;
4788: case ADD_VALUES:
4789: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4790: const PetscInt point = points[2*p];
4791: const PetscInt *perm = perms ? perms[p] : NULL;
4792: const PetscScalar *flip = flips ? flips[p] : NULL;
4793: PetscSectionGetDof(section, point, &dof);
4794: updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array);
4795: } break;
4796: case ADD_ALL_VALUES:
4797: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4798: const PetscInt point = points[2*p];
4799: const PetscInt *perm = perms ? perms[p] : NULL;
4800: const PetscScalar *flip = flips ? flips[p] : NULL;
4801: PetscSectionGetDof(section, point, &dof);
4802: updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array);
4803: } break;
4804: case ADD_BC_VALUES:
4805: for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4806: const PetscInt point = points[2*p];
4807: const PetscInt *perm = perms ? perms[p] : NULL;
4808: const PetscScalar *flip = flips ? flips[p] : NULL;
4809: PetscSectionGetDof(section, point, &dof);
4810: updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array);
4811: } break;
4812: default:
4813: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4814: }
4815: PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4816: }
4817: /* Cleanup points */
4818: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4819: /* Cleanup array */
4820: VecRestoreArray(v, &array);
4821: return(0);
4822: }
4824: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4825: {
4826: PetscSection clSection;
4827: IS clPoints;
4828: PetscScalar *array;
4829: PetscInt *points = NULL;
4830: const PetscInt *clp, *clperm;
4831: PetscInt numFields, numPoints, p;
4832: PetscInt offset = 0, f;
4833: PetscErrorCode ierr;
4837: if (!section) {DMGetSection(dm, §ion);}
4840: PetscSectionGetNumFields(section, &numFields);
4841: /* Get points */
4842: PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4843: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4844: /* Get array */
4845: VecGetArray(v, &array);
4846: /* Get values */
4847: for (f = 0; f < numFields; ++f) {
4848: const PetscInt **perms = NULL;
4849: const PetscScalar **flips = NULL;
4851: if (!fieldActive[f]) {
4852: for (p = 0; p < numPoints*2; p += 2) {
4853: PetscInt fdof;
4854: PetscSectionGetFieldDof(section, points[p], f, &fdof);
4855: offset += fdof;
4856: }
4857: continue;
4858: }
4859: PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4860: switch (mode) {
4861: case INSERT_VALUES:
4862: for (p = 0; p < numPoints; p++) {
4863: const PetscInt point = points[2*p];
4864: const PetscInt *perm = perms ? perms[p] : NULL;
4865: const PetscScalar *flip = flips ? flips[p] : NULL;
4866: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4867: } break;
4868: case INSERT_ALL_VALUES:
4869: for (p = 0; p < numPoints; p++) {
4870: const PetscInt point = points[2*p];
4871: const PetscInt *perm = perms ? perms[p] : NULL;
4872: const PetscScalar *flip = flips ? flips[p] : NULL;
4873: updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4874: } break;
4875: case INSERT_BC_VALUES:
4876: for (p = 0; p < numPoints; p++) {
4877: const PetscInt point = points[2*p];
4878: const PetscInt *perm = perms ? perms[p] : NULL;
4879: const PetscScalar *flip = flips ? flips[p] : NULL;
4880: updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4881: } break;
4882: case ADD_VALUES:
4883: for (p = 0; p < numPoints; p++) {
4884: const PetscInt point = points[2*p];
4885: const PetscInt *perm = perms ? perms[p] : NULL;
4886: const PetscScalar *flip = flips ? flips[p] : NULL;
4887: updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4888: } break;
4889: case ADD_ALL_VALUES:
4890: for (p = 0; p < numPoints; p++) {
4891: const PetscInt point = points[2*p];
4892: const PetscInt *perm = perms ? perms[p] : NULL;
4893: const PetscScalar *flip = flips ? flips[p] : NULL;
4894: updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4895: } break;
4896: default:
4897: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4898: }
4899: PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4900: }
4901: /* Cleanup points */
4902: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4903: /* Cleanup array */
4904: VecRestoreArray(v, &array);
4905: return(0);
4906: }
4908: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4909: {
4910: PetscMPIInt rank;
4911: PetscInt i, j;
4915: MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4916: PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4917: for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4918: for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4919: numCIndices = numCIndices ? numCIndices : numRIndices;
4920: for (i = 0; i < numRIndices; i++) {
4921: PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4922: for (j = 0; j < numCIndices; j++) {
4923: #if defined(PETSC_USE_COMPLEX)
4924: PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4925: #else
4926: PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4927: #endif
4928: }
4929: PetscViewerASCIIPrintf(viewer, "\n");
4930: }
4931: return(0);
4932: }
4934: /* . off - The global offset of this point */
4935: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4936: {
4937: PetscInt dof; /* The number of unknowns on this point */
4938: PetscInt cdof; /* The number of constraints on this point */
4939: const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4940: PetscInt cind = 0, k;
4941: PetscErrorCode ierr;
4944: PetscSectionGetDof(section, point, &dof);
4945: PetscSectionGetConstraintDof(section, point, &cdof);
4946: if (!cdof || setBC) {
4947: if (perm) {
4948: for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4949: } else {
4950: for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4951: }
4952: } else {
4953: PetscSectionGetConstraintIndices(section, point, &cdofs);
4954: if (perm) {
4955: for (k = 0; k < dof; ++k) {
4956: if ((cind < cdof) && (k == cdofs[cind])) {
4957: /* Insert check for returning constrained indices */
4958: indices[*loff+perm[k]] = -(off+k+1);
4959: ++cind;
4960: } else {
4961: indices[*loff+perm[k]] = off+k-cind;
4962: }
4963: }
4964: } else {
4965: for (k = 0; k < dof; ++k) {
4966: if ((cind < cdof) && (k == cdofs[cind])) {
4967: /* Insert check for returning constrained indices */
4968: indices[*loff+k] = -(off+k+1);
4969: ++cind;
4970: } else {
4971: indices[*loff+k] = off+k-cind;
4972: }
4973: }
4974: }
4975: }
4976: *loff += dof;
4977: return(0);
4978: }
4980: /*
4981: This version only believes the point offset from the globalSection
4983: . off - The global offset of this point
4984: */
4985: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4986: {
4987: PetscInt numFields, foff, f;
4991: PetscSectionGetNumFields(section, &numFields);
4992: for (f = 0, foff = 0; f < numFields; ++f) {
4993: PetscInt fdof, cfdof;
4994: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4995: PetscInt cind = 0, b;
4996: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4998: PetscSectionGetFieldDof(section, point, f, &fdof);
4999: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5000: if (!cfdof || setBC) {
5001: if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
5002: else {for (b = 0; b < fdof; b++) {indices[foffs[f]+ b ] = off+foff+b;}}
5003: } else {
5004: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5005: if (perm) {
5006: for (b = 0; b < fdof; b++) {
5007: if ((cind < cfdof) && (b == fcdofs[cind])) {
5008: indices[foffs[f]+perm[b]] = -(off+foff+b+1);
5009: ++cind;
5010: } else {
5011: indices[foffs[f]+perm[b]] = off+foff+b-cind;
5012: }
5013: }
5014: } else {
5015: for (b = 0; b < fdof; b++) {
5016: if ((cind < cfdof) && (b == fcdofs[cind])) {
5017: indices[foffs[f]+b] = -(off+foff+b+1);
5018: ++cind;
5019: } else {
5020: indices[foffs[f]+b] = off+foff+b-cind;
5021: }
5022: }
5023: }
5024: }
5025: foff += (setBC ? fdof : (fdof - cfdof));
5026: foffs[f] += fdof;
5027: }
5028: return(0);
5029: }
5031: /*
5032: This version believes the globalSection offsets for each field, rather than just the point offset
5034: . foffs - The offset into 'indices' for each field, since it is segregated by field
5035: */
5036: PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
5037: {
5038: PetscInt numFields, foff, f;
5042: PetscSectionGetNumFields(section, &numFields);
5043: for (f = 0; f < numFields; ++f) {
5044: PetscInt fdof, cfdof;
5045: const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5046: PetscInt cind = 0, b;
5047: const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5049: PetscSectionGetFieldDof(section, point, f, &fdof);
5050: PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5051: PetscSectionGetFieldOffset(globalSection, point, f, &foff);
5052: if (!cfdof || setBC) {
5053: if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = foff+b;}}
5054: else {for (b = 0; b < fdof; b++) {indices[foffs[f]+ b ] = foff+b;}}
5055: } else {
5056: PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5057: if (perm) {
5058: for (b = 0; b < fdof; b++) {
5059: if ((cind < cfdof) && (b == fcdofs[cind])) {
5060: indices[foffs[f]+perm[b]] = -(foff+b+1);
5061: ++cind;
5062: } else {
5063: indices[foffs[f]+perm[b]] = foff+b-cind;
5064: }
5065: }
5066: } else {
5067: for (b = 0; b < fdof; b++) {
5068: if ((cind < cfdof) && (b == fcdofs[cind])) {
5069: indices[foffs[f]+b] = -(foff+b+1);
5070: ++cind;
5071: } else {
5072: indices[foffs[f]+b] = foff+b-cind;
5073: }
5074: }
5075: }
5076: }
5077: foffs[f] += fdof;
5078: }
5079: return(0);
5080: }
5082: 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)
5083: {
5084: Mat cMat;
5085: PetscSection aSec, cSec;
5086: IS aIS;
5087: PetscInt aStart = -1, aEnd = -1;
5088: const PetscInt *anchors;
5089: PetscInt numFields, f, p, q, newP = 0;
5090: PetscInt newNumPoints = 0, newNumIndices = 0;
5091: PetscInt *newPoints, *indices, *newIndices;
5092: PetscInt maxAnchor, maxDof;
5093: PetscInt newOffsets[32];
5094: PetscInt *pointMatOffsets[32];
5095: PetscInt *newPointOffsets[32];
5096: PetscScalar *pointMat[32];
5097: PetscScalar *newValues=NULL,*tmpValues;
5098: PetscBool anyConstrained = PETSC_FALSE;
5099: PetscErrorCode ierr;
5104: PetscSectionGetNumFields(section, &numFields);
5106: DMPlexGetAnchors(dm,&aSec,&aIS);
5107: /* if there are point-to-point constraints */
5108: if (aSec) {
5109: PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
5110: ISGetIndices(aIS,&anchors);
5111: PetscSectionGetChart(aSec,&aStart,&aEnd);
5112: /* figure out how many points are going to be in the new element matrix
5113: * (we allow double counting, because it's all just going to be summed
5114: * into the global matrix anyway) */
5115: for (p = 0; p < 2*numPoints; p+=2) {
5116: PetscInt b = points[p];
5117: PetscInt bDof = 0, bSecDof;
5119: PetscSectionGetDof(section,b,&bSecDof);
5120: if (!bSecDof) {
5121: continue;
5122: }
5123: if (b >= aStart && b < aEnd) {
5124: PetscSectionGetDof(aSec,b,&bDof);
5125: }
5126: if (bDof) {
5127: /* this point is constrained */
5128: /* it is going to be replaced by its anchors */
5129: PetscInt bOff, q;
5131: anyConstrained = PETSC_TRUE;
5132: newNumPoints += bDof;
5133: PetscSectionGetOffset(aSec,b,&bOff);
5134: for (q = 0; q < bDof; q++) {
5135: PetscInt a = anchors[bOff + q];
5136: PetscInt aDof;
5138: PetscSectionGetDof(section,a,&aDof);
5139: newNumIndices += aDof;
5140: for (f = 0; f < numFields; ++f) {
5141: PetscInt fDof;
5143: PetscSectionGetFieldDof(section, a, f, &fDof);
5144: newOffsets[f+1] += fDof;
5145: }
5146: }
5147: }
5148: else {
5149: /* this point is not constrained */
5150: newNumPoints++;
5151: newNumIndices += bSecDof;
5152: for (f = 0; f < numFields; ++f) {
5153: PetscInt fDof;
5155: PetscSectionGetFieldDof(section, b, f, &fDof);
5156: newOffsets[f+1] += fDof;
5157: }
5158: }
5159: }
5160: }
5161: if (!anyConstrained) {
5162: if (outNumPoints) *outNumPoints = 0;
5163: if (outNumIndices) *outNumIndices = 0;
5164: if (outPoints) *outPoints = NULL;
5165: if (outValues) *outValues = NULL;
5166: if (aSec) {ISRestoreIndices(aIS,&anchors);}
5167: return(0);
5168: }
5170: if (outNumPoints) *outNumPoints = newNumPoints;
5171: if (outNumIndices) *outNumIndices = newNumIndices;
5173: for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
5175: if (!outPoints && !outValues) {
5176: if (offsets) {
5177: for (f = 0; f <= numFields; f++) {
5178: offsets[f] = newOffsets[f];
5179: }
5180: }
5181: if (aSec) {ISRestoreIndices(aIS,&anchors);}
5182: return(0);
5183: }
5185: if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
5187: DMGetDefaultConstraints(dm, &cSec, &cMat);
5189: /* workspaces */
5190: if (numFields) {
5191: for (f = 0; f < numFields; f++) {
5192: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5193: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5194: }
5195: }
5196: else {
5197: DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5198: DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5199: }
5201: /* get workspaces for the point-to-point matrices */
5202: if (numFields) {
5203: PetscInt totalOffset, totalMatOffset;
5205: for (p = 0; p < numPoints; p++) {
5206: PetscInt b = points[2*p];
5207: PetscInt bDof = 0, bSecDof;
5209: PetscSectionGetDof(section,b,&bSecDof);
5210: if (!bSecDof) {
5211: for (f = 0; f < numFields; f++) {
5212: newPointOffsets[f][p + 1] = 0;
5213: pointMatOffsets[f][p + 1] = 0;
5214: }
5215: continue;
5216: }
5217: if (b >= aStart && b < aEnd) {
5218: PetscSectionGetDof(aSec, b, &bDof);
5219: }
5220: if (bDof) {
5221: for (f = 0; f < numFields; f++) {
5222: PetscInt fDof, q, bOff, allFDof = 0;
5224: PetscSectionGetFieldDof(section, b, f, &fDof);
5225: PetscSectionGetOffset(aSec, b, &bOff);
5226: for (q = 0; q < bDof; q++) {
5227: PetscInt a = anchors[bOff + q];
5228: PetscInt aFDof;
5230: PetscSectionGetFieldDof(section, a, f, &aFDof);
5231: allFDof += aFDof;
5232: }
5233: newPointOffsets[f][p+1] = allFDof;
5234: pointMatOffsets[f][p+1] = fDof * allFDof;
5235: }
5236: }
5237: else {
5238: for (f = 0; f < numFields; f++) {
5239: PetscInt fDof;
5241: PetscSectionGetFieldDof(section, b, f, &fDof);
5242: newPointOffsets[f][p+1] = fDof;
5243: pointMatOffsets[f][p+1] = 0;
5244: }
5245: }
5246: }
5247: for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5248: newPointOffsets[f][0] = totalOffset;
5249: pointMatOffsets[f][0] = totalMatOffset;
5250: for (p = 0; p < numPoints; p++) {
5251: newPointOffsets[f][p+1] += newPointOffsets[f][p];
5252: pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5253: }
5254: totalOffset = newPointOffsets[f][numPoints];
5255: totalMatOffset = pointMatOffsets[f][numPoints];
5256: DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5257: }
5258: }
5259: else {
5260: for (p = 0; p < numPoints; p++) {
5261: PetscInt b = points[2*p];
5262: PetscInt bDof = 0, bSecDof;
5264: PetscSectionGetDof(section,b,&bSecDof);
5265: if (!bSecDof) {
5266: newPointOffsets[0][p + 1] = 0;
5267: pointMatOffsets[0][p + 1] = 0;
5268: continue;
5269: }
5270: if (b >= aStart && b < aEnd) {
5271: PetscSectionGetDof(aSec, b, &bDof);
5272: }
5273: if (bDof) {
5274: PetscInt bOff, q, allDof = 0;
5276: PetscSectionGetOffset(aSec, b, &bOff);
5277: for (q = 0; q < bDof; q++) {
5278: PetscInt a = anchors[bOff + q], aDof;
5280: PetscSectionGetDof(section, a, &aDof);
5281: allDof += aDof;
5282: }
5283: newPointOffsets[0][p+1] = allDof;
5284: pointMatOffsets[0][p+1] = bSecDof * allDof;
5285: }
5286: else {
5287: newPointOffsets[0][p+1] = bSecDof;
5288: pointMatOffsets[0][p+1] = 0;
5289: }
5290: }
5291: newPointOffsets[0][0] = 0;
5292: pointMatOffsets[0][0] = 0;
5293: for (p = 0; p < numPoints; p++) {
5294: newPointOffsets[0][p+1] += newPointOffsets[0][p];
5295: pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5296: }
5297: DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5298: }
5300: /* output arrays */
5301: DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5303: /* get the point-to-point matrices; construct newPoints */
5304: PetscSectionGetMaxDof(aSec, &maxAnchor);
5305: PetscSectionGetMaxDof(section, &maxDof);
5306: DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5307: DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5308: if (numFields) {
5309: for (p = 0, newP = 0; p < numPoints; p++) {
5310: PetscInt b = points[2*p];
5311: PetscInt o = points[2*p+1];
5312: PetscInt bDof = 0, bSecDof;
5314: PetscSectionGetDof(section, b, &bSecDof);
5315: if (!bSecDof) {
5316: continue;
5317: }
5318: if (b >= aStart && b < aEnd) {
5319: PetscSectionGetDof(aSec, b, &bDof);
5320: }
5321: if (bDof) {
5322: PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5324: fStart[0] = 0;
5325: fEnd[0] = 0;
5326: for (f = 0; f < numFields; f++) {
5327: PetscInt fDof;
5329: PetscSectionGetFieldDof(cSec, b, f, &fDof);
5330: fStart[f+1] = fStart[f] + fDof;
5331: fEnd[f+1] = fStart[f+1];
5332: }
5333: PetscSectionGetOffset(cSec, b, &bOff);
5334: DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);
5336: fAnchorStart[0] = 0;
5337: fAnchorEnd[0] = 0;
5338: for (f = 0; f < numFields; f++) {
5339: PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5341: fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5342: fAnchorEnd[f+1] = fAnchorStart[f + 1];
5343: }
5344: PetscSectionGetOffset(aSec, b, &bOff);
5345: for (q = 0; q < bDof; q++) {
5346: PetscInt a = anchors[bOff + q], aOff;
5348: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5349: newPoints[2*(newP + q)] = a;
5350: newPoints[2*(newP + q) + 1] = 0;
5351: PetscSectionGetOffset(section, a, &aOff);
5352: DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5353: }
5354: newP += bDof;
5356: if (outValues) {
5357: /* get the point-to-point submatrix */
5358: for (f = 0; f < numFields; f++) {
5359: MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5360: }
5361: }
5362: }
5363: else {
5364: newPoints[2 * newP] = b;
5365: newPoints[2 * newP + 1] = o;
5366: newP++;
5367: }
5368: }
5369: } else {
5370: for (p = 0; p < numPoints; p++) {
5371: PetscInt b = points[2*p];
5372: PetscInt o = points[2*p+1];
5373: PetscInt bDof = 0, bSecDof;
5375: PetscSectionGetDof(section, b, &bSecDof);
5376: if (!bSecDof) {
5377: continue;
5378: }
5379: if (b >= aStart && b < aEnd) {
5380: PetscSectionGetDof(aSec, b, &bDof);
5381: }
5382: if (bDof) {
5383: PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5385: PetscSectionGetOffset(cSec, b, &bOff);
5386: DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);
5388: PetscSectionGetOffset (aSec, b, &bOff);
5389: for (q = 0; q < bDof; q++) {
5390: PetscInt a = anchors[bOff + q], aOff;
5392: /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5394: newPoints[2*(newP + q)] = a;
5395: newPoints[2*(newP + q) + 1] = 0;
5396: PetscSectionGetOffset(section, a, &aOff);
5397: DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5398: }
5399: newP += bDof;
5401: /* get the point-to-point submatrix */
5402: if (outValues) {
5403: MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5404: }
5405: }
5406: else {
5407: newPoints[2 * newP] = b;
5408: newPoints[2 * newP + 1] = o;
5409: newP++;
5410: }
5411: }
5412: }
5414: if (outValues) {
5415: DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5416: PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5417: /* multiply constraints on the right */
5418: if (numFields) {
5419: for (f = 0; f < numFields; f++) {
5420: PetscInt oldOff = offsets[f];
5422: for (p = 0; p < numPoints; p++) {
5423: PetscInt cStart = newPointOffsets[f][p];
5424: PetscInt b = points[2 * p];
5425: PetscInt c, r, k;
5426: PetscInt dof;
5428: PetscSectionGetFieldDof(section,b,f,&dof);
5429: if (!dof) {
5430: continue;
5431: }
5432: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5433: PetscInt nCols = newPointOffsets[f][p+1]-cStart;
5434: const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5436: for (r = 0; r < numIndices; r++) {
5437: for (c = 0; c < nCols; c++) {
5438: for (k = 0; k < dof; k++) {
5439: tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5440: }
5441: }
5442: }
5443: }
5444: else {
5445: /* copy this column as is */
5446: for (r = 0; r < numIndices; r++) {
5447: for (c = 0; c < dof; c++) {
5448: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5449: }
5450: }
5451: }
5452: oldOff += dof;
5453: }
5454: }
5455: }
5456: else {
5457: PetscInt oldOff = 0;
5458: for (p = 0; p < numPoints; p++) {
5459: PetscInt cStart = newPointOffsets[0][p];
5460: PetscInt b = points[2 * p];
5461: PetscInt c, r, k;
5462: PetscInt dof;
5464: PetscSectionGetDof(section,b,&dof);
5465: if (!dof) {
5466: continue;
5467: }
5468: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5469: PetscInt nCols = newPointOffsets[0][p+1]-cStart;
5470: const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5472: for (r = 0; r < numIndices; r++) {
5473: for (c = 0; c < nCols; c++) {
5474: for (k = 0; k < dof; k++) {
5475: tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5476: }
5477: }
5478: }
5479: }
5480: else {
5481: /* copy this column as is */
5482: for (r = 0; r < numIndices; r++) {
5483: for (c = 0; c < dof; c++) {
5484: tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5485: }
5486: }
5487: }
5488: oldOff += dof;
5489: }
5490: }
5492: if (multiplyLeft) {
5493: DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5494: PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5495: /* multiply constraints transpose on the left */
5496: if (numFields) {
5497: for (f = 0; f < numFields; f++) {
5498: PetscInt oldOff = offsets[f];
5500: for (p = 0; p < numPoints; p++) {
5501: PetscInt rStart = newPointOffsets[f][p];
5502: PetscInt b = points[2 * p];
5503: PetscInt c, r, k;
5504: PetscInt dof;
5506: PetscSectionGetFieldDof(section,b,f,&dof);
5507: if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5508: PetscInt nRows = newPointOffsets[f][p+1]-rStart;
5509: const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5511: for (r = 0; r < nRows; r++) {
5512: for (c = 0; c < newNumIndices; c++) {
5513: for (k = 0; k < dof; k++) {
5514: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5515: }
5516: }
5517: }
5518: }
5519: else {
5520: /* copy this row as is */
5521: for (r = 0; r < dof; r++) {
5522: for (c = 0; c < newNumIndices; c++) {
5523: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5524: }
5525: }
5526: }
5527: oldOff += dof;
5528: }
5529: }
5530: }
5531: else {
5532: PetscInt oldOff = 0;
5534: for (p = 0; p < numPoints; p++) {
5535: PetscInt rStart = newPointOffsets[0][p];
5536: PetscInt b = points[2 * p];
5537: PetscInt c, r, k;
5538: PetscInt dof;
5540: PetscSectionGetDof(section,b,&dof);
5541: if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5542: PetscInt nRows = newPointOffsets[0][p+1]-rStart;
5543: const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5545: for (r = 0; r < nRows; r++) {
5546: for (c = 0; c < newNumIndices; c++) {
5547: for (k = 0; k < dof; k++) {
5548: newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5549: }
5550: }
5551: }
5552: }
5553: else {
5554: /* copy this row as is */
5555: for (r = 0; r < dof; r++) {
5556: for (c = 0; c < newNumIndices; c++) {
5557: newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5558: }
5559: }
5560: }
5561: oldOff += dof;
5562: }
5563: }
5565: DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5566: }
5567: else {
5568: newValues = tmpValues;
5569: }
5570: }
5572: /* clean up */
5573: DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5574: DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5576: if (numFields) {
5577: for (f = 0; f < numFields; f++) {
5578: DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5579: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5580: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5581: }
5582: }
5583: else {
5584: DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5585: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5586: DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5587: }
5588: ISRestoreIndices(aIS,&anchors);
5590: /* output */
5591: if (outPoints) {
5592: *outPoints = newPoints;
5593: }
5594: else {
5595: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5596: }
5597: if (outValues) {
5598: *outValues = newValues;
5599: }
5600: for (f = 0; f <= numFields; f++) {
5601: offsets[f] = newOffsets[f];
5602: }
5603: return(0);
5604: }
5606: /*@C
5607: DMPlexGetClosureIndices - Get the global indices in a vector v for all points in the closure of the given point
5609: Not collective
5611: Input Parameters:
5612: + dm - The DM
5613: . section - The section describing the layout in v, or NULL to use the default section
5614: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5615: - point - The mesh point
5617: Output parameters:
5618: + numIndices - The number of indices
5619: . indices - The indices
5620: - outOffsets - Field offset if not NULL
5622: Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5624: Level: advanced
5626: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5627: @*/
5628: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5629: {
5630: PetscSection clSection;
5631: IS clPoints;
5632: const PetscInt *clp;
5633: const PetscInt **perms[32] = {NULL};
5634: PetscInt *points = NULL, *pointsNew;
5635: PetscInt numPoints, numPointsNew;
5636: PetscInt offsets[32];
5637: PetscInt Nf, Nind, NindNew, off, globalOff, f, p;
5638: PetscErrorCode ierr;
5646: PetscSectionGetNumFields(section, &Nf);
5647: if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5648: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5649: /* Get points in closure */
5650: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5651: /* Get number of indices and indices per field */
5652: for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5653: PetscInt dof, fdof;
5655: PetscSectionGetDof(section, points[p], &dof);
5656: for (f = 0; f < Nf; ++f) {
5657: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5658: offsets[f+1] += fdof;
5659: }
5660: Nind += dof;
5661: }
5662: for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5663: if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5664: if (!Nf) offsets[1] = Nind;
5665: /* Get dual space symmetries */
5666: for (f = 0; f < PetscMax(1,Nf); f++) {
5667: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5668: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5669: }
5670: /* Correct for hanging node constraints */
5671: {
5672: DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5673: if (numPointsNew) {
5674: for (f = 0; f < PetscMax(1,Nf); f++) {
5675: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5676: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5677: }
5678: for (f = 0; f < PetscMax(1,Nf); f++) {
5679: if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5680: else {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5681: }
5682: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5683: numPoints = numPointsNew;
5684: Nind = NindNew;
5685: points = pointsNew;
5686: }
5687: }
5688: /* Calculate indices */
5689: DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5690: if (Nf) {
5691: if (outOffsets) {
5692: PetscInt f;
5694: for (f = 0; f <= Nf; f++) {
5695: outOffsets[f] = offsets[f];
5696: }
5697: }
5698: for (p = 0; p < numPoints; p++) {
5699: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5700: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5701: }
5702: } else {
5703: for (p = 0, off = 0; p < numPoints; p++) {
5704: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5706: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5707: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5708: }
5709: }
5710: /* Cleanup points */
5711: for (f = 0; f < PetscMax(1,Nf); f++) {
5712: if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5713: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5714: }
5715: if (numPointsNew) {
5716: DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5717: } else {
5718: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5719: }
5720: if (numIndices) *numIndices = Nind;
5721: return(0);
5722: }
5724: /*@C
5725: DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5727: Not collective
5729: Input Parameters:
5730: + dm - The DM
5731: . section - The section describing the layout in v, or NULL to use the default section
5732: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5733: . point - The mesh point
5734: . numIndices - The number of indices
5735: . indices - The indices
5736: - outOffsets - Field offset if not NULL
5738: Level: advanced
5740: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5741: @*/
5742: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5743: {
5749: DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5750: return(0);
5751: }
5753: /*@C
5754: DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5756: Not collective
5758: Input Parameters:
5759: + dm - The DM
5760: . section - The section describing the layout in v, or NULL to use the default section
5761: . globalSection - The section describing the layout in v, or NULL to use the default global section
5762: . A - The matrix
5763: . point - The point in the DM
5764: . values - The array of values
5765: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5767: Fortran Notes:
5768: This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5770: Level: intermediate
5772: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5773: @*/
5774: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5775: {
5776: DM_Plex *mesh = (DM_Plex*) dm->data;
5777: PetscSection clSection;
5778: IS clPoints;
5779: PetscInt *points = NULL, *newPoints;
5780: const PetscInt *clp;
5781: PetscInt *indices;
5782: PetscInt offsets[32];
5783: const PetscInt **perms[32] = {NULL};
5784: const PetscScalar **flips[32] = {NULL};
5785: PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5786: PetscScalar *valCopy = NULL;
5787: PetscScalar *newValues;
5788: PetscErrorCode ierr;
5792: if (!section) {DMGetSection(dm, §ion);}
5794: if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5797: PetscSectionGetNumFields(section, &numFields);
5798: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5799: PetscMemzero(offsets, 32 * sizeof(PetscInt));
5800: DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5801: for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5802: PetscInt fdof;
5804: PetscSectionGetDof(section, points[p], &dof);
5805: for (f = 0; f < numFields; ++f) {
5806: PetscSectionGetFieldDof(section, points[p], f, &fdof);
5807: offsets[f+1] += fdof;
5808: }
5809: numIndices += dof;
5810: }
5811: for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5813: if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5814: /* Get symmetries */
5815: for (f = 0; f < PetscMax(1,numFields); f++) {
5816: if (numFields) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5817: else {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5818: if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5819: PetscInt foffset = offsets[f];
5821: for (p = 0; p < numPoints; p++) {
5822: PetscInt point = points[2*p], fdof;
5823: const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5825: if (!numFields) {
5826: PetscSectionGetDof(section,point,&fdof);
5827: } else {
5828: PetscSectionGetFieldDof(section,point,f,&fdof);
5829: }
5830: if (flip) {
5831: PetscInt i, j, k;
5833: if (!valCopy) {
5834: DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5835: for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5836: values = valCopy;
5837: }
5838: for (i = 0; i < fdof; i++) {
5839: PetscScalar fval = flip[i];
5841: for (k = 0; k < numIndices; k++) {
5842: valCopy[numIndices * (foffset + i) + k] *= fval;
5843: valCopy[numIndices * k + (foffset + i)] *= fval;
5844: }
5845: }
5846: }
5847: foffset += fdof;
5848: }
5849: }
5850: }
5851: DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5852: if (newNumPoints) {
5853: if (valCopy) {
5854: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5855: }
5856: for (f = 0; f < PetscMax(1,numFields); f++) {
5857: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5858: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5859: }
5860: for (f = 0; f < PetscMax(1,numFields); f++) {
5861: if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5862: else {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5863: }
5864: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5865: numPoints = newNumPoints;
5866: numIndices = newNumIndices;
5867: points = newPoints;
5868: values = newValues;
5869: }
5870: DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5871: if (numFields) {
5872: PetscBool useFieldOffsets;
5874: PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
5875: if (useFieldOffsets) {
5876: for (p = 0; p < numPoints; p++) {
5877: DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, indices);
5878: }
5879: } else {
5880: for (p = 0; p < numPoints; p++) {
5881: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5882: DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5883: }
5884: }
5885: } else {
5886: for (p = 0, off = 0; p < numPoints; p++) {
5887: const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5888: PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5889: DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5890: }
5891: }
5892: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5893: MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5894: if (mesh->printFEM > 1) {
5895: PetscInt i;
5896: PetscPrintf(PETSC_COMM_SELF, " Indices:");
5897: for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5898: PetscPrintf(PETSC_COMM_SELF, "\n");
5899: }
5900: if (ierr) {
5901: PetscMPIInt rank;
5902: PetscErrorCode ierr2;
5904: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5905: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5906: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5907: ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5908:
5909: }
5910: for (f = 0; f < PetscMax(1,numFields); f++) {
5911: if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5912: else {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5913: }
5914: if (newNumPoints) {
5915: DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5916: DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5917: }
5918: else {
5919: if (valCopy) {
5920: DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5921: }
5922: DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5923: }
5924: DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5925: return(0);
5926: }
5928: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5929: {
5930: DM_Plex *mesh = (DM_Plex*) dmf->data;
5931: PetscInt *fpoints = NULL, *ftotpoints = NULL;
5932: PetscInt *cpoints = NULL;
5933: PetscInt *findices, *cindices;
5934: PetscInt foffsets[32], coffsets[32];
5935: CellRefiner cellRefiner;
5936: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5937: PetscErrorCode ierr;
5942: if (!fsection) {DMGetSection(dmf, &fsection);}
5944: if (!csection) {DMGetSection(dmc, &csection);}
5946: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
5948: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
5951: PetscSectionGetNumFields(fsection, &numFields);
5952: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5953: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5954: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5955: /* Column indices */
5956: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5957: maxFPoints = numCPoints;
5958: /* Compress out points not in the section */
5959: /* TODO: Squeeze out points with 0 dof as well */
5960: PetscSectionGetChart(csection, &pStart, &pEnd);
5961: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5962: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5963: cpoints[q*2] = cpoints[p];
5964: cpoints[q*2+1] = cpoints[p+1];
5965: ++q;
5966: }
5967: }
5968: numCPoints = q;
5969: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5970: PetscInt fdof;
5972: PetscSectionGetDof(csection, cpoints[p], &dof);
5973: if (!dof) continue;
5974: for (f = 0; f < numFields; ++f) {
5975: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5976: coffsets[f+1] += fdof;
5977: }
5978: numCIndices += dof;
5979: }
5980: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5981: /* Row indices */
5982: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5983: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5984: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5985: for (r = 0, q = 0; r < numSubcells; ++r) {
5986: /* TODO Map from coarse to fine cells */
5987: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5988: /* Compress out points not in the section */
5989: PetscSectionGetChart(fsection, &pStart, &pEnd);
5990: for (p = 0; p < numFPoints*2; p += 2) {
5991: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5992: PetscSectionGetDof(fsection, fpoints[p], &dof);
5993: if (!dof) continue;
5994: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5995: if (s < q) continue;
5996: ftotpoints[q*2] = fpoints[p];
5997: ftotpoints[q*2+1] = fpoints[p+1];
5998: ++q;
5999: }
6000: }
6001: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6002: }
6003: numFPoints = q;
6004: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6005: PetscInt fdof;
6007: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6008: if (!dof) continue;
6009: for (f = 0; f < numFields; ++f) {
6010: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6011: foffsets[f+1] += fdof;
6012: }
6013: numFIndices += dof;
6014: }
6015: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6017: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6018: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6019: DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6020: DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6021: if (numFields) {
6022: const PetscInt **permsF[32] = {NULL};
6023: const PetscInt **permsC[32] = {NULL};
6025: for (f = 0; f < numFields; f++) {
6026: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6027: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6028: }
6029: for (p = 0; p < numFPoints; p++) {
6030: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6031: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
6032: }
6033: for (p = 0; p < numCPoints; p++) {
6034: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6035: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6036: }
6037: for (f = 0; f < numFields; f++) {
6038: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6039: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6040: }
6041: } else {
6042: const PetscInt **permsF = NULL;
6043: const PetscInt **permsC = NULL;
6045: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6046: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6047: for (p = 0, off = 0; p < numFPoints; p++) {
6048: const PetscInt *perm = permsF ? permsF[p] : NULL;
6050: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6051: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6052: }
6053: for (p = 0, off = 0; p < numCPoints; p++) {
6054: const PetscInt *perm = permsC ? permsC[p] : NULL;
6056: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6057: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6058: }
6059: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6060: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6061: }
6062: if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
6063: /* TODO: flips */
6064: MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6065: if (ierr) {
6066: PetscMPIInt rank;
6067: PetscErrorCode ierr2;
6069: ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6070: ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6071: ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6072: ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6073: ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6074:
6075: }
6076: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6077: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6078: DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6079: DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6080: return(0);
6081: }
6083: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6084: {
6085: PetscInt *fpoints = NULL, *ftotpoints = NULL;
6086: PetscInt *cpoints = NULL;
6087: PetscInt foffsets[32], coffsets[32];
6088: CellRefiner cellRefiner;
6089: PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6095: if (!fsection) {DMGetSection(dmf, &fsection);}
6097: if (!csection) {DMGetSection(dmc, &csection);}
6099: if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6101: if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6103: PetscSectionGetNumFields(fsection, &numFields);
6104: if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6105: PetscMemzero(foffsets, 32 * sizeof(PetscInt));
6106: PetscMemzero(coffsets, 32 * sizeof(PetscInt));
6107: /* Column indices */
6108: DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6109: maxFPoints = numCPoints;
6110: /* Compress out points not in the section */
6111: /* TODO: Squeeze out points with 0 dof as well */
6112: PetscSectionGetChart(csection, &pStart, &pEnd);
6113: for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6114: if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6115: cpoints[q*2] = cpoints[p];
6116: cpoints[q*2+1] = cpoints[p+1];
6117: ++q;
6118: }
6119: }
6120: numCPoints = q;
6121: for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6122: PetscInt fdof;
6124: PetscSectionGetDof(csection, cpoints[p], &dof);
6125: if (!dof) continue;
6126: for (f = 0; f < numFields; ++f) {
6127: PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6128: coffsets[f+1] += fdof;
6129: }
6130: numCIndices += dof;
6131: }
6132: for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6133: /* Row indices */
6134: DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6135: CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6136: DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6137: for (r = 0, q = 0; r < numSubcells; ++r) {
6138: /* TODO Map from coarse to fine cells */
6139: DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6140: /* Compress out points not in the section */
6141: PetscSectionGetChart(fsection, &pStart, &pEnd);
6142: for (p = 0; p < numFPoints*2; p += 2) {
6143: if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6144: PetscSectionGetDof(fsection, fpoints[p], &dof);
6145: if (!dof) continue;
6146: for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6147: if (s < q) continue;
6148: ftotpoints[q*2] = fpoints[p];
6149: ftotpoints[q*2+1] = fpoints[p+1];
6150: ++q;
6151: }
6152: }
6153: DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6154: }
6155: numFPoints = q;
6156: for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6157: PetscInt fdof;
6159: PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6160: if (!dof) continue;
6161: for (f = 0; f < numFields; ++f) {
6162: PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6163: foffsets[f+1] += fdof;
6164: }
6165: numFIndices += dof;
6166: }
6167: for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6169: if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6170: if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6171: if (numFields) {
6172: const PetscInt **permsF[32] = {NULL};
6173: const PetscInt **permsC[32] = {NULL};
6175: for (f = 0; f < numFields; f++) {
6176: PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6177: PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6178: }
6179: for (p = 0; p < numFPoints; p++) {
6180: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6181: DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
6182: }
6183: for (p = 0; p < numCPoints; p++) {
6184: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6185: DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6186: }
6187: for (f = 0; f < numFields; f++) {
6188: PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6189: PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6190: }
6191: } else {
6192: const PetscInt **permsF = NULL;
6193: const PetscInt **permsC = NULL;
6195: PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6196: PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6197: for (p = 0, off = 0; p < numFPoints; p++) {
6198: const PetscInt *perm = permsF ? permsF[p] : NULL;
6200: PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6201: DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6202: }
6203: for (p = 0, off = 0; p < numCPoints; p++) {
6204: const PetscInt *perm = permsC ? permsC[p] : NULL;
6206: PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6207: DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6208: }
6209: PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6210: PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6211: }
6212: DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6213: DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6214: return(0);
6215: }
6217: /*@
6218: DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6220: Input Parameter:
6221: . dm - The DMPlex object
6223: Output Parameters:
6224: + cMax - The first hybrid cell
6225: . fMax - The first hybrid face
6226: . eMax - The first hybrid edge
6227: - vMax - The first hybrid vertex
6229: Level: developer
6231: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6232: @*/
6233: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6234: {
6235: DM_Plex *mesh = (DM_Plex*) dm->data;
6236: PetscInt dim;
6241: DMGetDimension(dm, &dim);
6242: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6243: if (cMax) *cMax = mesh->hybridPointMax[dim];
6244: if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6245: if (eMax) *eMax = mesh->hybridPointMax[1];
6246: if (vMax) *vMax = mesh->hybridPointMax[0];
6247: return(0);
6248: }
6250: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6251: {
6252: IS is, his;
6253: PetscInt first = 0, stride;
6254: PetscBool isStride;
6258: DMLabelGetStratumIS(depthLabel, d, &is);
6259: PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6260: if (isStride) {
6261: ISStrideGetInfo(is, &first, &stride);
6262: }
6263: if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6264: ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6265: DMLabelSetStratumIS(dimLabel, d, his);
6266: ISDestroy(&his);
6267: ISDestroy(&is);
6268: return(0);
6269: }
6271: /*@
6272: DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6274: Input Parameters:
6275: . dm - The DMPlex object
6276: . cMax - The first hybrid cell
6277: . fMax - The first hybrid face
6278: . eMax - The first hybrid edge
6279: - vMax - The first hybrid vertex
6281: Level: developer
6283: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6284: @*/
6285: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6286: {
6287: DM_Plex *mesh = (DM_Plex*) dm->data;
6288: PetscInt dim;
6293: DMGetDimension(dm, &dim);
6294: if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6295: if (cMax >= 0) mesh->hybridPointMax[dim] = cMax;
6296: if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6297: if (eMax >= 0) mesh->hybridPointMax[1] = eMax;
6298: if (vMax >= 0) mesh->hybridPointMax[0] = vMax;
6299: return(0);
6300: }
6302: /*@C
6303: DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6305: Input Parameter:
6306: . dm - The DMPlex object
6308: Output Parameter:
6309: . cellHeight - The height of a cell
6311: Level: developer
6313: .seealso DMPlexSetVTKCellHeight()
6314: @*/
6315: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6316: {
6317: DM_Plex *mesh = (DM_Plex*) dm->data;
6322: *cellHeight = mesh->vtkCellHeight;
6323: return(0);
6324: }
6326: /*@C
6327: DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6329: Input Parameters:
6330: + dm - The DMPlex object
6331: - cellHeight - The height of a cell
6333: Level: developer
6335: .seealso DMPlexGetVTKCellHeight()
6336: @*/
6337: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6338: {
6339: DM_Plex *mesh = (DM_Plex*) dm->data;
6343: mesh->vtkCellHeight = cellHeight;
6344: return(0);
6345: }
6347: /* We can easily have a form that takes an IS instead */
6348: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6349: {
6350: PetscSection section, globalSection;
6351: PetscInt *numbers, p;
6355: PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);
6356: PetscSectionSetChart(section, pStart, pEnd);
6357: for (p = pStart; p < pEnd; ++p) {
6358: PetscSectionSetDof(section, p, 1);
6359: }
6360: PetscSectionSetUp(section);
6361: PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6362: PetscMalloc1(pEnd - pStart, &numbers);
6363: for (p = pStart; p < pEnd; ++p) {
6364: PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6365: if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6366: else numbers[p-pStart] += shift;
6367: }
6368: ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6369: if (globalSize) {
6370: PetscLayout layout;
6371: PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6372: PetscLayoutGetSize(layout, globalSize);
6373: PetscLayoutDestroy(&layout);
6374: }
6375: PetscSectionDestroy(§ion);
6376: PetscSectionDestroy(&globalSection);
6377: return(0);
6378: }
6380: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6381: {
6382: PetscInt cellHeight, cStart, cEnd, cMax;
6386: DMPlexGetVTKCellHeight(dm, &cellHeight);
6387: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6388: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6389: if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6390: DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6391: return(0);
6392: }
6394: /*@C
6395: DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6397: Input Parameter:
6398: . dm - The DMPlex object
6400: Output Parameter:
6401: . globalCellNumbers - Global cell numbers for all cells on this process
6403: Level: developer
6405: .seealso DMPlexGetVertexNumbering()
6406: @*/
6407: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6408: {
6409: DM_Plex *mesh = (DM_Plex*) dm->data;
6414: if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6415: *globalCellNumbers = mesh->globalCellNumbers;
6416: return(0);
6417: }
6419: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6420: {
6421: PetscInt vStart, vEnd, vMax;
6426: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6427: DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6428: if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6429: DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6430: return(0);
6431: }
6433: /*@C
6434: DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process
6436: Input Parameter:
6437: . dm - The DMPlex object
6439: Output Parameter:
6440: . globalVertexNumbers - Global vertex numbers for all vertices on this process
6442: Level: developer
6444: .seealso DMPlexGetCellNumbering()
6445: @*/
6446: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6447: {
6448: DM_Plex *mesh = (DM_Plex*) dm->data;
6453: if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6454: *globalVertexNumbers = mesh->globalVertexNumbers;
6455: return(0);
6456: }
6458: /*@C
6459: DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6461: Input Parameter:
6462: . dm - The DMPlex object
6464: Output Parameter:
6465: . globalPointNumbers - Global numbers for all points on this process
6467: Level: developer
6469: .seealso DMPlexGetCellNumbering()
6470: @*/
6471: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6472: {
6473: IS nums[4];
6474: PetscInt depths[4];
6475: PetscInt depth, d, shift = 0;
6480: DMPlexGetDepth(dm, &depth);
6481: /* For unstratified meshes use dim instead of depth */
6482: if (depth < 0) {DMGetDimension(dm, &depth);}
6483: depths[0] = depth; depths[1] = 0;
6484: for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6485: for (d = 0; d <= depth; ++d) {
6486: PetscInt pStart, pEnd, gsize;
6488: DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6489: DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6490: shift += gsize;
6491: }
6492: ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6493: for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6494: return(0);
6495: }
6498: /*@
6499: DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6501: Input Parameter:
6502: . dm - The DMPlex object
6504: Output Parameter:
6505: . ranks - The rank field
6507: Options Database Keys:
6508: . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6510: Level: intermediate
6512: .seealso: DMView()
6513: @*/
6514: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6515: {
6516: DM rdm;
6517: PetscDS prob;
6518: PetscFE fe;
6519: PetscScalar *r;
6520: PetscMPIInt rank;
6521: PetscInt dim, cStart, cEnd, c;
6525: MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6526: DMClone(dm, &rdm);
6527: DMGetDimension(rdm, &dim);
6528: PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, NULL, -1, &fe);
6529: PetscObjectSetName((PetscObject) fe, "rank");
6530: DMGetDS(rdm, &prob);
6531: PetscDSSetDiscretization(prob, 0, (PetscObject) fe);
6532: PetscFEDestroy(&fe);
6533: DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6534: DMCreateGlobalVector(rdm, ranks);
6535: PetscObjectSetName((PetscObject) *ranks, "partition");
6536: VecGetArray(*ranks, &r);
6537: for (c = cStart; c < cEnd; ++c) {
6538: PetscScalar *lr;
6540: DMPlexPointGlobalRef(rdm, c, r, &lr);
6541: *lr = rank;
6542: }
6543: VecRestoreArray(*ranks, &r);
6544: DMDestroy(&rdm);
6545: return(0);
6546: }
6548: /*@
6549: DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6551: Input Parameter:
6552: . dm - The DMPlex object
6554: Note: This is a useful diagnostic when creating meshes programmatically.
6556: Level: developer
6558: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6559: @*/
6560: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6561: {
6562: PetscSection coneSection, supportSection;
6563: const PetscInt *cone, *support;
6564: PetscInt coneSize, c, supportSize, s;
6565: PetscInt pStart, pEnd, p, csize, ssize;
6566: PetscErrorCode ierr;
6570: DMPlexGetConeSection(dm, &coneSection);
6571: DMPlexGetSupportSection(dm, &supportSection);
6572: /* Check that point p is found in the support of its cone points, and vice versa */
6573: DMPlexGetChart(dm, &pStart, &pEnd);
6574: for (p = pStart; p < pEnd; ++p) {
6575: DMPlexGetConeSize(dm, p, &coneSize);
6576: DMPlexGetCone(dm, p, &cone);
6577: for (c = 0; c < coneSize; ++c) {
6578: PetscBool dup = PETSC_FALSE;
6579: PetscInt d;
6580: for (d = c-1; d >= 0; --d) {
6581: if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6582: }
6583: DMPlexGetSupportSize(dm, cone[c], &supportSize);
6584: DMPlexGetSupport(dm, cone[c], &support);
6585: for (s = 0; s < supportSize; ++s) {
6586: if (support[s] == p) break;
6587: }
6588: if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6589: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6590: for (s = 0; s < coneSize; ++s) {
6591: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6592: }
6593: PetscPrintf(PETSC_COMM_SELF, "\n");
6594: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6595: for (s = 0; s < supportSize; ++s) {
6596: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6597: }
6598: PetscPrintf(PETSC_COMM_SELF, "\n");
6599: if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6600: else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6601: }
6602: }
6603: DMPlexGetSupportSize(dm, p, &supportSize);
6604: DMPlexGetSupport(dm, p, &support);
6605: for (s = 0; s < supportSize; ++s) {
6606: DMPlexGetConeSize(dm, support[s], &coneSize);
6607: DMPlexGetCone(dm, support[s], &cone);
6608: for (c = 0; c < coneSize; ++c) {
6609: if (cone[c] == p) break;
6610: }
6611: if (c >= coneSize) {
6612: PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6613: for (c = 0; c < supportSize; ++c) {
6614: PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6615: }
6616: PetscPrintf(PETSC_COMM_SELF, "\n");
6617: PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6618: for (c = 0; c < coneSize; ++c) {
6619: PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6620: }
6621: PetscPrintf(PETSC_COMM_SELF, "\n");
6622: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6623: }
6624: }
6625: }
6626: PetscSectionGetStorageSize(coneSection, &csize);
6627: PetscSectionGetStorageSize(supportSection, &ssize);
6628: if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6629: return(0);
6630: }
6632: /*@
6633: DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6635: Input Parameters:
6636: + dm - The DMPlex object
6637: . isSimplex - Are the cells simplices or tensor products
6638: - cellHeight - Normally 0
6640: Note: This is a useful diagnostic when creating meshes programmatically.
6642: Level: developer
6644: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6645: @*/
6646: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6647: {
6648: PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6653: DMGetDimension(dm, &dim);
6654: switch (dim) {
6655: case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6656: case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6657: case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6658: default:
6659: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6660: }
6661: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6662: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6663: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6664: cMax = cMax >= 0 ? cMax : cEnd;
6665: for (c = cStart; c < cMax; ++c) {
6666: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6668: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6669: for (cl = 0; cl < closureSize*2; cl += 2) {
6670: const PetscInt p = closure[cl];
6671: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6672: }
6673: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6674: if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D", c, coneSize, numCorners);
6675: }
6676: for (c = cMax; c < cEnd; ++c) {
6677: PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6679: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6680: for (cl = 0; cl < closureSize*2; cl += 2) {
6681: const PetscInt p = closure[cl];
6682: if ((p >= vStart) && (p < vEnd)) ++coneSize;
6683: }
6684: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6685: if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has %D vertices > %D", c, coneSize, numHybridCorners);
6686: }
6687: return(0);
6688: }
6690: /*@
6691: DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6693: Input Parameters:
6694: + dm - The DMPlex object
6695: . isSimplex - Are the cells simplices or tensor products
6696: - cellHeight - Normally 0
6698: Note: This is a useful diagnostic when creating meshes programmatically.
6700: Level: developer
6702: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6703: @*/
6704: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6705: {
6706: PetscInt pMax[4];
6707: PetscInt dim, vStart, vEnd, cStart, cEnd, c, h;
6712: DMGetDimension(dm, &dim);
6713: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6714: DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6715: for (h = cellHeight; h < dim; ++h) {
6716: DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6717: for (c = cStart; c < cEnd; ++c) {
6718: const PetscInt *cone, *ornt, *faces;
6719: PetscInt numFaces, faceSize, coneSize,f;
6720: PetscInt *closure = NULL, closureSize, cl, numCorners = 0;
6722: if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6723: DMPlexGetConeSize(dm, c, &coneSize);
6724: DMPlexGetCone(dm, c, &cone);
6725: DMPlexGetConeOrientation(dm, c, &ornt);
6726: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6727: for (cl = 0; cl < closureSize*2; cl += 2) {
6728: const PetscInt p = closure[cl];
6729: if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6730: }
6731: DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6732: if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6733: for (f = 0; f < numFaces; ++f) {
6734: PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6736: DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6737: for (cl = 0; cl < fclosureSize*2; cl += 2) {
6738: const PetscInt p = fclosure[cl];
6739: if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6740: }
6741: 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);
6742: for (v = 0; v < fnumCorners; ++v) {
6743: 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]);
6744: }
6745: DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6746: }
6747: DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6748: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6749: }
6750: }
6751: return(0);
6752: }
6754: /* Pointwise interpolation
6755: Just code FEM for now
6756: u^f = I u^c
6757: sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6758: u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6759: I_{ij} = psi^f_i phi^c_j
6760: */
6761: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6762: {
6763: PetscSection gsc, gsf;
6764: PetscInt m, n;
6765: void *ctx;
6766: DM cdm;
6767: PetscBool regular, ismatis;
6771: DMGetGlobalSection(dmFine, &gsf);
6772: PetscSectionGetConstrainedStorageSize(gsf, &m);
6773: DMGetGlobalSection(dmCoarse, &gsc);
6774: PetscSectionGetConstrainedStorageSize(gsc, &n);
6776: PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
6777: MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6778: MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6779: MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
6780: DMGetApplicationContext(dmFine, &ctx);
6782: DMGetCoarseDM(dmFine, &cdm);
6783: DMPlexGetRegularRefinement(dmFine, ®ular);
6784: if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6785: else {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6786: MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6787: /* Use naive scaling */
6788: DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6789: return(0);
6790: }
6792: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6793: {
6795: VecScatter ctx;
6798: DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6799: MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6800: VecScatterDestroy(&ctx);
6801: return(0);
6802: }
6804: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6805: {
6806: PetscSection gsc, gsf;
6807: PetscInt m, n;
6808: void *ctx;
6809: DM cdm;
6810: PetscBool regular;
6814: DMGetGlobalSection(dmFine, &gsf);
6815: PetscSectionGetConstrainedStorageSize(gsf, &m);
6816: DMGetGlobalSection(dmCoarse, &gsc);
6817: PetscSectionGetConstrainedStorageSize(gsc, &n);
6819: MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6820: MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6821: MatSetType(*mass, dmCoarse->mattype);
6822: DMGetApplicationContext(dmFine, &ctx);
6824: DMGetCoarseDM(dmFine, &cdm);
6825: DMPlexGetRegularRefinement(dmFine, ®ular);
6826: if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6827: else {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6828: MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6829: return(0);
6830: }
6832: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6833: {
6834: PetscSection section;
6835: IS *bcPoints, *bcComps;
6836: PetscBool *isFE;
6837: PetscInt *bcFields, *numComp, *numDof;
6838: PetscInt depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6839: PetscInt cStart, cEnd, cEndInterior;
6843: DMGetNumFields(dm, &numFields);
6844: /* FE and FV boundary conditions are handled slightly differently */
6845: PetscMalloc1(numFields, &isFE);
6846: for (f = 0; f < numFields; ++f) {
6847: PetscObject obj;
6848: PetscClassId id;
6850: DMGetField(dm, f, &obj);
6851: PetscObjectGetClassId(obj, &id);
6852: if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;}
6853: else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6854: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6855: }
6856: /* Allocate boundary point storage for FEM boundaries */
6857: DMPlexGetDepth(dm, &depth);
6858: DMGetDimension(dm, &dim);
6859: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6860: DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6861: PetscDSGetNumBoundary(dm->prob, &numBd);
6862: 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)");
6863: for (bd = 0; bd < numBd; ++bd) {
6864: PetscInt field;
6865: DMBoundaryConditionType type;
6866: const char *labelName;
6867: DMLabel label;
6869: PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6870: DMGetLabel(dm,labelName,&label);
6871: if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6872: }
6873: /* Add ghost cell boundaries for FVM */
6874: for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6875: PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6876: /* Constrain ghost cells for FV */
6877: for (f = 0; f < numFields; ++f) {
6878: PetscInt *newidx, c;
6880: if (isFE[f] || cEndInterior < 0) continue;
6881: PetscMalloc1(cEnd-cEndInterior,&newidx);
6882: for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6883: bcFields[bc] = f;
6884: ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6885: }
6886: /* Handle FEM Dirichlet boundaries */
6887: for (bd = 0; bd < numBd; ++bd) {
6888: const char *bdLabel;
6889: DMLabel label;
6890: const PetscInt *comps;
6891: const PetscInt *values;
6892: PetscInt bd2, field, numComps, numValues;
6893: DMBoundaryConditionType type;
6894: PetscBool duplicate = PETSC_FALSE;
6896: PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6897: DMGetLabel(dm, bdLabel, &label);
6898: if (!isFE[field] || !label) continue;
6899: /* Only want to modify label once */
6900: for (bd2 = 0; bd2 < bd; ++bd2) {
6901: const char *bdname;
6902: PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6903: PetscStrcmp(bdname, bdLabel, &duplicate);
6904: if (duplicate) break;
6905: }
6906: if (!duplicate && (isFE[field])) {
6907: /* don't complete cells, which are just present to give orientation to the boundary */
6908: DMPlexLabelComplete(dm, label);
6909: }
6910: /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6911: if (type & DM_BC_ESSENTIAL) {
6912: PetscInt *newidx;
6913: PetscInt n, newn = 0, p, v;
6915: bcFields[bc] = field;
6916: if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6917: for (v = 0; v < numValues; ++v) {
6918: IS tmp;
6919: const PetscInt *idx;
6921: DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6922: if (!tmp) continue;
6923: ISGetLocalSize(tmp, &n);
6924: ISGetIndices(tmp, &idx);
6925: if (isFE[field]) {
6926: for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6927: } else {
6928: for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6929: }
6930: ISRestoreIndices(tmp, &idx);
6931: ISDestroy(&tmp);
6932: }
6933: PetscMalloc1(newn,&newidx);
6934: newn = 0;
6935: for (v = 0; v < numValues; ++v) {
6936: IS tmp;
6937: const PetscInt *idx;
6939: DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6940: if (!tmp) continue;
6941: ISGetLocalSize(tmp, &n);
6942: ISGetIndices(tmp, &idx);
6943: if (isFE[field]) {
6944: for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6945: } else {
6946: for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6947: }
6948: ISRestoreIndices(tmp, &idx);
6949: ISDestroy(&tmp);
6950: }
6951: ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6952: }
6953: }
6954: /* Handle discretization */
6955: PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6956: for (f = 0; f < numFields; ++f) {
6957: PetscObject obj;
6959: DMGetField(dm, f, &obj);
6960: if (isFE[f]) {
6961: PetscFE fe = (PetscFE) obj;
6962: const PetscInt *numFieldDof;
6963: PetscInt d;
6965: PetscFEGetNumComponents(fe, &numComp[f]);
6966: PetscFEGetNumDof(fe, &numFieldDof);
6967: for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6968: } else {
6969: PetscFV fv = (PetscFV) obj;
6971: PetscFVGetNumComponents(fv, &numComp[f]);
6972: numDof[f*(dim+1)+dim] = numComp[f];
6973: }
6974: }
6975: for (f = 0; f < numFields; ++f) {
6976: PetscInt d;
6977: for (d = 1; d < dim; ++d) {
6978: 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.");
6979: }
6980: }
6981: DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, §ion);
6982: for (f = 0; f < numFields; ++f) {
6983: PetscFE fe;
6984: const char *name;
6986: DMGetField(dm, f, (PetscObject *) &fe);
6987: PetscObjectGetName((PetscObject) fe, &name);
6988: PetscSectionSetFieldName(section, f, name);
6989: }
6990: DMSetSection(dm, section);
6991: PetscSectionDestroy(§ion);
6992: for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6993: PetscFree3(bcFields,bcPoints,bcComps);
6994: PetscFree2(numComp,numDof);
6995: PetscFree(isFE);
6996: return(0);
6997: }
6999: /*@
7000: DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7002: Input Parameter:
7003: . dm - The DMPlex object
7005: Output Parameter:
7006: . regular - The flag
7008: Level: intermediate
7010: .seealso: DMPlexSetRegularRefinement()
7011: @*/
7012: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7013: {
7017: *regular = ((DM_Plex *) dm->data)->regularRefinement;
7018: return(0);
7019: }
7021: /*@
7022: DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7024: Input Parameters:
7025: + dm - The DMPlex object
7026: - regular - The flag
7028: Level: intermediate
7030: .seealso: DMPlexGetRegularRefinement()
7031: @*/
7032: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7033: {
7036: ((DM_Plex *) dm->data)->regularRefinement = regular;
7037: return(0);
7038: }
7040: /* anchors */
7041: /*@
7042: DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to
7043: call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
7045: not collective
7047: Input Parameters:
7048: . dm - The DMPlex object
7050: Output Parameters:
7051: + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
7052: - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
7055: Level: intermediate
7057: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7058: @*/
7059: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7060: {
7061: DM_Plex *plex = (DM_Plex *)dm->data;
7066: if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7067: if (anchorSection) *anchorSection = plex->anchorSection;
7068: if (anchorIS) *anchorIS = plex->anchorIS;
7069: return(0);
7070: }
7072: /*@
7073: DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions,
7074: when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
7075: point's degrees of freedom to be a linear combination of other points' degrees of freedom.
7077: After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
7078: DMGetConstraints() and filling in the entries in the constraint matrix.
7080: collective on dm
7082: Input Parameters:
7083: + dm - The DMPlex object
7084: . 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).
7085: - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative).
7087: The reference counts of anchorSection and anchorIS are incremented.
7089: Level: intermediate
7091: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7092: @*/
7093: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7094: {
7095: DM_Plex *plex = (DM_Plex *)dm->data;
7096: PetscMPIInt result;
7101: if (anchorSection) {
7103: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7104: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7105: }
7106: if (anchorIS) {
7108: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7109: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7110: }
7112: PetscObjectReference((PetscObject)anchorSection);
7113: PetscSectionDestroy(&plex->anchorSection);
7114: plex->anchorSection = anchorSection;
7116: PetscObjectReference((PetscObject)anchorIS);
7117: ISDestroy(&plex->anchorIS);
7118: plex->anchorIS = anchorIS;
7120: #if defined(PETSC_USE_DEBUG)
7121: if (anchorIS && anchorSection) {
7122: PetscInt size, a, pStart, pEnd;
7123: const PetscInt *anchors;
7125: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7126: ISGetLocalSize(anchorIS,&size);
7127: ISGetIndices(anchorIS,&anchors);
7128: for (a = 0; a < size; a++) {
7129: PetscInt p;
7131: p = anchors[a];
7132: if (p >= pStart && p < pEnd) {
7133: PetscInt dof;
7135: PetscSectionGetDof(anchorSection,p,&dof);
7136: if (dof) {
7137: PetscErrorCode ierr2;
7139: ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7140: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7141: }
7142: }
7143: }
7144: ISRestoreIndices(anchorIS,&anchors);
7145: }
7146: #endif
7147: /* reset the generic constraints */
7148: DMSetDefaultConstraints(dm,NULL,NULL);
7149: return(0);
7150: }
7152: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7153: {
7154: PetscSection anchorSection;
7155: PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
7160: DMPlexGetAnchors(dm,&anchorSection,NULL);
7161: PetscSectionCreate(PETSC_COMM_SELF,cSec);
7162: PetscSectionGetNumFields(section,&numFields);
7163: if (numFields) {
7164: PetscInt f;
7165: PetscSectionSetNumFields(*cSec,numFields);
7167: for (f = 0; f < numFields; f++) {
7168: PetscInt numComp;
7170: PetscSectionGetFieldComponents(section,f,&numComp);
7171: PetscSectionSetFieldComponents(*cSec,f,numComp);
7172: }
7173: }
7174: PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7175: PetscSectionGetChart(section,&sStart,&sEnd);
7176: pStart = PetscMax(pStart,sStart);
7177: pEnd = PetscMin(pEnd,sEnd);
7178: pEnd = PetscMax(pStart,pEnd);
7179: PetscSectionSetChart(*cSec,pStart,pEnd);
7180: for (p = pStart; p < pEnd; p++) {
7181: PetscSectionGetDof(anchorSection,p,&dof);
7182: if (dof) {
7183: PetscSectionGetDof(section,p,&dof);
7184: PetscSectionSetDof(*cSec,p,dof);
7185: for (f = 0; f < numFields; f++) {
7186: PetscSectionGetFieldDof(section,p,f,&dof);
7187: PetscSectionSetFieldDof(*cSec,p,f,dof);
7188: }
7189: }
7190: }
7191: PetscSectionSetUp(*cSec);
7192: return(0);
7193: }
7195: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7196: {
7197: PetscSection aSec;
7198: PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7199: const PetscInt *anchors;
7200: PetscInt numFields, f;
7201: IS aIS;
7206: PetscSectionGetStorageSize(cSec, &m);
7207: PetscSectionGetStorageSize(section, &n);
7208: MatCreate(PETSC_COMM_SELF,cMat);
7209: MatSetSizes(*cMat,m,n,m,n);
7210: MatSetType(*cMat,MATSEQAIJ);
7211: DMPlexGetAnchors(dm,&aSec,&aIS);
7212: ISGetIndices(aIS,&anchors);
7213: /* cSec will be a subset of aSec and section */
7214: PetscSectionGetChart(cSec,&pStart,&pEnd);
7215: PetscMalloc1(m+1,&i);
7216: i[0] = 0;
7217: PetscSectionGetNumFields(section,&numFields);
7218: for (p = pStart; p < pEnd; p++) {
7219: PetscInt rDof, rOff, r;
7221: PetscSectionGetDof(aSec,p,&rDof);
7222: if (!rDof) continue;
7223: PetscSectionGetOffset(aSec,p,&rOff);
7224: if (numFields) {
7225: for (f = 0; f < numFields; f++) {
7226: annz = 0;
7227: for (r = 0; r < rDof; r++) {
7228: a = anchors[rOff + r];
7229: PetscSectionGetFieldDof(section,a,f,&aDof);
7230: annz += aDof;
7231: }
7232: PetscSectionGetFieldDof(cSec,p,f,&dof);
7233: PetscSectionGetFieldOffset(cSec,p,f,&off);
7234: for (q = 0; q < dof; q++) {
7235: i[off + q + 1] = i[off + q] + annz;
7236: }
7237: }
7238: }
7239: else {
7240: annz = 0;
7241: for (q = 0; q < dof; q++) {
7242: a = anchors[off + q];
7243: PetscSectionGetDof(section,a,&aDof);
7244: annz += aDof;
7245: }
7246: PetscSectionGetDof(cSec,p,&dof);
7247: PetscSectionGetOffset(cSec,p,&off);
7248: for (q = 0; q < dof; q++) {
7249: i[off + q + 1] = i[off + q] + annz;
7250: }
7251: }
7252: }
7253: nnz = i[m];
7254: PetscMalloc1(nnz,&j);
7255: offset = 0;
7256: for (p = pStart; p < pEnd; p++) {
7257: if (numFields) {
7258: for (f = 0; f < numFields; f++) {
7259: PetscSectionGetFieldDof(cSec,p,f,&dof);
7260: for (q = 0; q < dof; q++) {
7261: PetscInt rDof, rOff, r;
7262: PetscSectionGetDof(aSec,p,&rDof);
7263: PetscSectionGetOffset(aSec,p,&rOff);
7264: for (r = 0; r < rDof; r++) {
7265: PetscInt s;
7267: a = anchors[rOff + r];
7268: PetscSectionGetFieldDof(section,a,f,&aDof);
7269: PetscSectionGetFieldOffset(section,a,f,&aOff);
7270: for (s = 0; s < aDof; s++) {
7271: j[offset++] = aOff + s;
7272: }
7273: }
7274: }
7275: }
7276: }
7277: else {
7278: PetscSectionGetDof(cSec,p,&dof);
7279: for (q = 0; q < dof; q++) {
7280: PetscInt rDof, rOff, r;
7281: PetscSectionGetDof(aSec,p,&rDof);
7282: PetscSectionGetOffset(aSec,p,&rOff);
7283: for (r = 0; r < rDof; r++) {
7284: PetscInt s;
7286: a = anchors[rOff + r];
7287: PetscSectionGetDof(section,a,&aDof);
7288: PetscSectionGetOffset(section,a,&aOff);
7289: for (s = 0; s < aDof; s++) {
7290: j[offset++] = aOff + s;
7291: }
7292: }
7293: }
7294: }
7295: }
7296: MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7297: PetscFree(i);
7298: PetscFree(j);
7299: ISRestoreIndices(aIS,&anchors);
7300: return(0);
7301: }
7303: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7304: {
7305: DM_Plex *plex = (DM_Plex *)dm->data;
7306: PetscSection anchorSection, section, cSec;
7307: Mat cMat;
7312: DMPlexGetAnchors(dm,&anchorSection,NULL);
7313: if (anchorSection) {
7314: PetscDS ds;
7315: PetscInt nf;
7317: DMGetSection(dm,§ion);
7318: DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7319: DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7320: DMGetDS(dm,&ds);
7321: PetscDSGetNumFields(ds,&nf);
7322: if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7323: DMSetDefaultConstraints(dm,cSec,cMat);
7324: PetscSectionDestroy(&cSec);
7325: MatDestroy(&cMat);
7326: }
7327: return(0);
7328: }
7330: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7331: {
7332: PetscDS prob;
7333: IS subis;
7334: PetscSection section, subsection;
7338: DMGetDefaultSection(dm, §ion);
7339: if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7340: if (!subdm) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7341: /* Create subdomain */
7342: DMPlexFilter(dm, label, value, subdm);
7343: /* Create submodel */
7344: DMPlexCreateSubpointIS(*subdm, &subis);
7345: PetscSectionCreateSubmeshSection(section, subis, &subsection);
7346: ISDestroy(&subis);
7347: DMSetDefaultSection(*subdm, subsection);
7348: PetscSectionDestroy(&subsection);
7349: DMGetDS(dm, &prob);
7350: DMSetDS(*subdm, prob);
7351: /* Create map from submodel to global model */
7352: if (is) {
7353: PetscSection sectionGlobal, subsectionGlobal;
7354: IS spIS;
7355: const PetscInt *spmap;
7356: PetscInt *subIndices;
7357: PetscInt subSize = 0, subOff = 0, pStart, pEnd, p;
7358: PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
7360: DMPlexCreateSubpointIS(*subdm, &spIS);
7361: ISGetIndices(spIS, &spmap);
7362: PetscSectionGetNumFields(section, &Nf);
7363: DMGetDefaultGlobalSection(dm, §ionGlobal);
7364: DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);
7365: PetscSectionGetChart(subsection, &pStart, &pEnd);
7366: for (p = pStart; p < pEnd; ++p) {
7367: PetscInt gdof, pSubSize = 0;
7369: PetscSectionGetDof(sectionGlobal, p, &gdof);
7370: if (gdof > 0) {
7371: for (f = 0; f < Nf; ++f) {
7372: PetscInt fdof, fcdof;
7374: PetscSectionGetFieldDof(subsection, p, f, &fdof);
7375: PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7376: pSubSize += fdof-fcdof;
7377: }
7378: subSize += pSubSize;
7379: if (pSubSize) {
7380: if (bs < 0) {
7381: bs = pSubSize;
7382: } else if (bs != pSubSize) {
7383: /* Layout does not admit a pointwise block size */
7384: bs = 1;
7385: }
7386: }
7387: }
7388: }
7389: /* Must have same blocksize on all procs (some might have no points) */
7390: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7391: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7392: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7393: else {bs = bsMinMax[0];}
7394: PetscMalloc1(subSize, &subIndices);
7395: for (p = pStart; p < pEnd; ++p) {
7396: PetscInt gdof, goff;
7398: PetscSectionGetDof(subsectionGlobal, p, &gdof);
7399: if (gdof > 0) {
7400: const PetscInt point = spmap[p];
7402: PetscSectionGetOffset(sectionGlobal, point, &goff);
7403: for (f = 0; f < Nf; ++f) {
7404: PetscInt fdof, fcdof, fc, f2, poff = 0;
7406: /* Can get rid of this loop by storing field information in the global section */
7407: for (f2 = 0; f2 < f; ++f2) {
7408: PetscSectionGetFieldDof(section, p, f2, &fdof);
7409: PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7410: poff += fdof-fcdof;
7411: }
7412: PetscSectionGetFieldDof(section, p, f, &fdof);
7413: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7414: for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7415: subIndices[subOff] = goff+poff+fc;
7416: }
7417: }
7418: }
7419: }
7420: ISRestoreIndices(spIS, &spmap);
7421: ISDestroy(&spIS);
7422: ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7423: if (bs > 1) {
7424: /* We need to check that the block size does not come from non-contiguous fields */
7425: PetscInt i, j, set = 1;
7426: for (i = 0; i < subSize; i += bs) {
7427: for (j = 0; j < bs; ++j) {
7428: if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7429: }
7430: }
7431: if (set) {ISSetBlockSize(*is, bs);}
7432: }
7433: /* Attach nullspace */
7434: for (f = 0; f < Nf; ++f) {
7435: (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7436: if ((*subdm)->nullspaceConstructors[f]) break;
7437: }
7438: if (f < Nf) {
7439: MatNullSpace nullSpace;
7441: (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7442: PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7443: MatNullSpaceDestroy(&nullSpace);
7444: }
7445: }
7446: return(0);
7447: }