1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 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> 9 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_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF; 12 13 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 14 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. 18 19 Collective 20 21 Input Parameters: 22 . dm - The DMPlex object 23 24 Output Parameters: 25 . dmRefined - The refined DMPlex object 26 27 Note: Returns NULL if the mesh is already a tensor product mesh. 28 29 Level: intermediate 30 31 .seealso: DMPlexCreate(), DMPlexSetRefinementUniform() 32 @*/ 33 PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined) 34 { 35 CellRefiner cellRefiner; 36 DMPolytopeType ct; 37 PetscInt dim, cMax, fMax, cStart, cEnd; 38 PetscBool lop, allnoop, localized; 39 PetscErrorCode ierr; 40 41 PetscFunctionBegin; 42 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 43 PetscValidPointer(dmRefined, 1); 44 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 45 ierr = DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);CHKERRQ(ierr); 46 ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr); 47 if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP; 48 else { 49 ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr); 50 switch (ct) { 51 case DM_POLYTOPE_POINT: 52 case DM_POLYTOPE_SEGMENT: 53 cellRefiner = REFINER_NOOP;break; 54 case DM_POLYTOPE_TRIANGLE: 55 if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D; 56 else cellRefiner = REFINER_SIMPLEX_TO_HEX_2D; 57 break; 58 case DM_POLYTOPE_QUADRILATERAL: 59 if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D; 60 else cellRefiner = REFINER_NOOP; 61 break; 62 case DM_POLYTOPE_TETRAHEDRON: 63 if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D; 64 else cellRefiner = REFINER_SIMPLEX_TO_HEX_3D; 65 break; 66 case DM_POLYTOPE_TRI_PRISM_TENSOR: 67 cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;break; 68 case DM_POLYTOPE_HEXAHEDRON: 69 if (cMax >= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Simplex2Tensor in 3D with Hybrid mesh not yet done"); 70 else cellRefiner = REFINER_NOOP; 71 break; 72 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle cell polytope type %s", DMPolytopeTypes[ct]); 73 } 74 } 75 /* return if we don't need to refine */ 76 lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE; 77 ierr = MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 78 if (allnoop) { 79 *dmRefined = NULL; 80 PetscFunctionReturn(0); 81 } 82 ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr); 83 ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr); 84 ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr); 85 if (localized) { 86 ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr); 87 } 88 PetscFunctionReturn(0); 89 } 90 91 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 92 { 93 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cMax; 94 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 95 PetscErrorCode ierr; 96 97 PetscFunctionBegin; 98 *ft = PETSC_VTK_INVALID; 99 ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr); 100 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 101 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 102 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 103 cEnd = cMax < 0 ? cEnd : cMax; 104 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 105 if (field >= 0) { 106 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);CHKERRQ(ierr);} 107 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);CHKERRQ(ierr);} 108 } else { 109 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vcdof[0]);CHKERRQ(ierr);} 110 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &vcdof[1]);CHKERRQ(ierr);} 111 } 112 ierr = MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 113 if (globalvcdof[0]) { 114 *sStart = vStart; 115 *sEnd = vEnd; 116 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 117 else *ft = PETSC_VTK_POINT_FIELD; 118 } else if (globalvcdof[1]) { 119 *sStart = cStart; 120 *sEnd = cEnd; 121 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 122 else *ft = PETSC_VTK_CELL_FIELD; 123 } else { 124 if (field >= 0) { 125 const char *fieldname; 126 127 ierr = PetscSectionGetFieldName(section, field, &fieldname);CHKERRQ(ierr); 128 ierr = PetscInfo2((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname);CHKERRQ(ierr); 129 } else { 130 ierr = PetscInfo((PetscObject) dm, "Could not classify VTK output typp of section\"%s\"\n");CHKERRQ(ierr); 131 } 132 } 133 PetscFunctionReturn(0); 134 } 135 136 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 137 { 138 DM dm; 139 PetscSection s; 140 PetscDraw draw, popup; 141 DM cdm; 142 PetscSection coordSection; 143 Vec coordinates; 144 const PetscScalar *coords, *array; 145 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 146 PetscReal vbound[2], time; 147 PetscBool isnull, flg; 148 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 149 const char *name; 150 char title[PETSC_MAX_PATH_LEN]; 151 PetscErrorCode ierr; 152 153 PetscFunctionBegin; 154 ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr); 155 ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr); 156 if (isnull) PetscFunctionReturn(0); 157 158 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 159 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 160 if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim); 161 ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr); 162 ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr); 163 ierr = DMGetCoarsenLevel(dm, &level);CHKERRQ(ierr); 164 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 165 ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr); 166 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 167 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 168 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 169 170 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 171 ierr = DMGetOutputSequenceNumber(dm, &step, &time);CHKERRQ(ierr); 172 173 ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); 174 ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); 175 for (c = 0; c < N; c += dim) { 176 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 177 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 178 } 179 ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); 180 ierr = PetscDrawClear(draw);CHKERRQ(ierr); 181 182 /* Could implement something like DMDASelectFields() */ 183 for (f = 0; f < Nf; ++f) { 184 DM fdm = dm; 185 Vec fv = v; 186 IS fis; 187 char prefix[PETSC_MAX_PATH_LEN]; 188 const char *fname; 189 190 ierr = PetscSectionGetFieldComponents(s, f, &Nc);CHKERRQ(ierr); 191 ierr = PetscSectionGetFieldName(s, f, &fname);CHKERRQ(ierr); 192 193 if (v->hdr.prefix) {ierr = PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));CHKERRQ(ierr);} 194 else {prefix[0] = '\0';} 195 if (Nf > 1) { 196 ierr = DMCreateSubDM(dm, 1, &f, &fis, &fdm);CHKERRQ(ierr); 197 ierr = VecGetSubVector(v, fis, &fv);CHKERRQ(ierr); 198 ierr = PetscStrlcat(prefix, fname,sizeof(prefix));CHKERRQ(ierr); 199 ierr = PetscStrlcat(prefix, "_",sizeof(prefix));CHKERRQ(ierr); 200 } 201 for (comp = 0; comp < Nc; ++comp, ++w) { 202 PetscInt nmax = 2; 203 204 ierr = PetscViewerDrawGetDraw(viewer, w, &draw);CHKERRQ(ierr); 205 if (Nc > 1) {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);CHKERRQ(ierr);} 206 else {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);CHKERRQ(ierr);} 207 ierr = PetscDrawSetTitle(draw, title);CHKERRQ(ierr); 208 209 /* TODO Get max and min only for this component */ 210 ierr = PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);CHKERRQ(ierr); 211 if (!flg) { 212 ierr = VecMin(fv, NULL, &vbound[0]);CHKERRQ(ierr); 213 ierr = VecMax(fv, NULL, &vbound[1]);CHKERRQ(ierr); 214 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 215 } 216 ierr = PetscDrawGetPopup(draw, &popup);CHKERRQ(ierr); 217 ierr = PetscDrawScalePopup(popup, vbound[0], vbound[1]);CHKERRQ(ierr); 218 ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr); 219 220 ierr = VecGetArrayRead(fv, &array);CHKERRQ(ierr); 221 for (c = cStart; c < cEnd; ++c) { 222 PetscScalar *coords = NULL, *a = NULL; 223 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 224 225 ierr = DMPlexPointLocalRead(fdm, c, array, &a);CHKERRQ(ierr); 226 if (a) { 227 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 228 color[1] = color[2] = color[3] = color[0]; 229 } else { 230 PetscScalar *vals = NULL; 231 PetscInt numVals, va; 232 233 ierr = DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr); 234 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); 235 switch (numVals/Nc) { 236 case 3: /* P1 Triangle */ 237 case 4: /* P1 Quadrangle */ 238 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 239 break; 240 case 6: /* P2 Triangle */ 241 case 8: /* P2 Quadrangle */ 242 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 243 break; 244 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc); 245 } 246 ierr = DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr); 247 } 248 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 249 switch (numCoords) { 250 case 6: 251 ierr = 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]);CHKERRQ(ierr); 252 break; 253 case 8: 254 ierr = 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]);CHKERRQ(ierr); 255 ierr = 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]);CHKERRQ(ierr); 256 break; 257 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords); 258 } 259 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 260 } 261 ierr = VecRestoreArrayRead(fv, &array);CHKERRQ(ierr); 262 ierr = PetscDrawFlush(draw);CHKERRQ(ierr); 263 ierr = PetscDrawPause(draw);CHKERRQ(ierr); 264 ierr = PetscDrawSave(draw);CHKERRQ(ierr); 265 } 266 if (Nf > 1) { 267 ierr = VecRestoreSubVector(v, fis, &fv);CHKERRQ(ierr); 268 ierr = ISDestroy(&fis);CHKERRQ(ierr); 269 ierr = DMDestroy(&fdm);CHKERRQ(ierr); 270 } 271 } 272 PetscFunctionReturn(0); 273 } 274 275 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 276 { 277 DM dm; 278 Vec locv; 279 const char *name; 280 PetscSection section; 281 PetscInt pStart, pEnd; 282 PetscInt numFields; 283 PetscViewerVTKFieldType ft; 284 PetscErrorCode ierr; 285 286 PetscFunctionBegin; 287 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 288 ierr = DMCreateLocalVector(dm, &locv);CHKERRQ(ierr); /* VTK viewer requires exclusive ownership of the vector */ 289 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 290 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 291 ierr = VecCopy(v, locv);CHKERRQ(ierr); 292 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 293 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 294 if (!numFields) { 295 ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr); 296 ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr); 297 } else { 298 PetscInt f; 299 300 for (f = 0; f < numFields; f++) { 301 ierr = DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft);CHKERRQ(ierr); 302 if (ft == PETSC_VTK_INVALID) continue; 303 ierr = PetscObjectReference((PetscObject)locv);CHKERRQ(ierr); 304 ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr); 305 } 306 ierr = VecDestroy(&locv);CHKERRQ(ierr); 307 } 308 PetscFunctionReturn(0); 309 } 310 311 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 312 { 313 DM dm; 314 PetscBool isvtk, ishdf5, isdraw, isglvis; 315 PetscErrorCode ierr; 316 317 PetscFunctionBegin; 318 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 319 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 320 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 321 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 322 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 323 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr); 324 if (isvtk || ishdf5 || isdraw || isglvis) { 325 PetscInt i,numFields; 326 PetscObject fe; 327 PetscBool fem = PETSC_FALSE; 328 Vec locv = v; 329 const char *name; 330 PetscInt step; 331 PetscReal time; 332 333 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 334 for (i=0; i<numFields; i++) { 335 ierr = DMGetField(dm, i, NULL, &fe);CHKERRQ(ierr); 336 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 337 } 338 if (fem) { 339 ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr); 340 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 341 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 342 ierr = VecCopy(v, locv);CHKERRQ(ierr); 343 ierr = DMGetOutputSequenceNumber(dm, NULL, &time);CHKERRQ(ierr); 344 ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);CHKERRQ(ierr); 345 } 346 if (isvtk) { 347 ierr = VecView_Plex_Local_VTK(locv, viewer);CHKERRQ(ierr); 348 } else if (ishdf5) { 349 #if defined(PETSC_HAVE_HDF5) 350 ierr = VecView_Plex_Local_HDF5_Internal(locv, viewer);CHKERRQ(ierr); 351 #else 352 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 353 #endif 354 } else if (isdraw) { 355 ierr = VecView_Plex_Local_Draw(locv, viewer);CHKERRQ(ierr); 356 } else if (isglvis) { 357 ierr = DMGetOutputSequenceNumber(dm, &step, NULL);CHKERRQ(ierr); 358 ierr = PetscViewerGLVisSetSnapId(viewer, step);CHKERRQ(ierr); 359 ierr = VecView_GLVis(locv, viewer);CHKERRQ(ierr); 360 } 361 if (fem) {ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);} 362 } else { 363 PetscBool isseq; 364 365 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 366 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 367 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 368 } 369 PetscFunctionReturn(0); 370 } 371 372 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 373 { 374 DM dm; 375 PetscBool isvtk, ishdf5, isdraw, isglvis; 376 PetscErrorCode ierr; 377 378 PetscFunctionBegin; 379 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 380 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 381 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 382 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 383 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 384 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr); 385 if (isvtk || isdraw || isglvis) { 386 Vec locv; 387 const char *name; 388 389 ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr); 390 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 391 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 392 ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 393 ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 394 ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr); 395 ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr); 396 } else if (ishdf5) { 397 #if defined(PETSC_HAVE_HDF5) 398 ierr = VecView_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr); 399 #else 400 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 401 #endif 402 } else { 403 PetscBool isseq; 404 405 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 406 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 407 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 408 } 409 PetscFunctionReturn(0); 410 } 411 412 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 413 { 414 DM dm; 415 MPI_Comm comm; 416 PetscViewerFormat format; 417 Vec v; 418 PetscBool isvtk, ishdf5; 419 PetscErrorCode ierr; 420 421 PetscFunctionBegin; 422 ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr); 423 ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr); 424 if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 425 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 426 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 427 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 428 if (format == PETSC_VIEWER_NATIVE) { 429 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 430 /* this need a better fix */ 431 if (dm->useNatural) { 432 if (dm->sfNatural) { 433 const char *vecname; 434 PetscInt n, nroots; 435 436 ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr); 437 ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 438 if (n == nroots) { 439 ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr); 440 ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr); 441 ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr); 442 ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr); 443 ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr); 444 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 445 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 446 } else v = originalv; 447 } else v = originalv; 448 449 if (ishdf5) { 450 #if defined(PETSC_HAVE_HDF5) 451 ierr = VecView_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr); 452 #else 453 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 454 #endif 455 } else if (isvtk) { 456 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 457 } else { 458 PetscBool isseq; 459 460 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 461 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 462 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 463 } 464 if (v != originalv) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);} 465 PetscFunctionReturn(0); 466 } 467 468 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 469 { 470 DM dm; 471 PetscBool ishdf5; 472 PetscErrorCode ierr; 473 474 PetscFunctionBegin; 475 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 476 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 477 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 478 if (ishdf5) { 479 DM dmBC; 480 Vec gv; 481 const char *name; 482 483 ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr); 484 ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr); 485 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 486 ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr); 487 ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr); 488 ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 489 ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 490 ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr); 491 } else { 492 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 493 } 494 PetscFunctionReturn(0); 495 } 496 497 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 498 { 499 DM dm; 500 PetscBool ishdf5; 501 PetscErrorCode ierr; 502 503 PetscFunctionBegin; 504 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 505 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 506 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 507 if (ishdf5) { 508 #if defined(PETSC_HAVE_HDF5) 509 ierr = VecLoad_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr); 510 #else 511 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 512 #endif 513 } else { 514 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 515 } 516 PetscFunctionReturn(0); 517 } 518 519 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 520 { 521 DM dm; 522 PetscViewerFormat format; 523 PetscBool ishdf5; 524 PetscErrorCode ierr; 525 526 PetscFunctionBegin; 527 ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr); 528 if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 529 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 530 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 531 if (format == PETSC_VIEWER_NATIVE) { 532 if (dm->useNatural) { 533 if (dm->sfNatural) { 534 if (ishdf5) { 535 #if defined(PETSC_HAVE_HDF5) 536 Vec v; 537 const char *vecname; 538 539 ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr); 540 ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr); 541 ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr); 542 ierr = VecLoad_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr); 543 ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr); 544 ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr); 545 ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr); 546 #else 547 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 548 #endif 549 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 550 } 551 } else { 552 ierr = VecLoad_Default(originalv, viewer);CHKERRQ(ierr); 553 } 554 } 555 PetscFunctionReturn(0); 556 } 557 558 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 559 { 560 PetscSection coordSection; 561 Vec coordinates; 562 DMLabel depthLabel, celltypeLabel; 563 const char *name[4]; 564 const PetscScalar *a; 565 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 566 PetscErrorCode ierr; 567 568 PetscFunctionBegin; 569 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 570 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 571 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 572 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 573 ierr = DMPlexGetCellTypeLabel(dm, &celltypeLabel);CHKERRQ(ierr); 574 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 575 ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr); 576 ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr); 577 name[0] = "vertex"; 578 name[1] = "edge"; 579 name[dim-1] = "face"; 580 name[dim] = "cell"; 581 for (c = cStart; c < cEnd; ++c) { 582 PetscInt *closure = NULL; 583 PetscInt closureSize, cl, ct; 584 585 ierr = DMLabelGetValue(celltypeLabel, c, &ct);CHKERRQ(ierr); 586 ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct]);CHKERRQ(ierr); 587 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 588 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 589 for (cl = 0; cl < closureSize*2; cl += 2) { 590 PetscInt point = closure[cl], depth, dof, off, d, p; 591 592 if ((point < pStart) || (point >= pEnd)) continue; 593 ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr); 594 if (!dof) continue; 595 ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr); 596 ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr); 597 ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr); 598 for (p = 0; p < dof/dim; ++p) { 599 ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr); 600 for (d = 0; d < dim; ++d) { 601 if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 602 ierr = PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr); 603 } 604 ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr); 605 } 606 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 607 } 608 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 609 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 610 } 611 ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr); 612 PetscFunctionReturn(0); 613 } 614 615 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 616 { 617 DM_Plex *mesh = (DM_Plex*) dm->data; 618 DM cdm; 619 DMLabel markers; 620 PetscSection coordSection; 621 Vec coordinates; 622 PetscViewerFormat format; 623 PetscErrorCode ierr; 624 625 PetscFunctionBegin; 626 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 627 ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr); 628 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 629 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 630 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 631 const char *name; 632 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 633 PetscInt pStart, pEnd, p; 634 PetscMPIInt rank, size; 635 636 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr); 637 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr); 638 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 639 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 640 ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr); 641 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 642 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 643 if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 644 else {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 645 if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);CHKERRQ(ierr);} 646 ierr = PetscViewerASCIIPrintf(viewer, "Supports:\n", name);CHKERRQ(ierr); 647 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 648 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);CHKERRQ(ierr); 649 for (p = pStart; p < pEnd; ++p) { 650 PetscInt dof, off, s; 651 652 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 653 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 654 for (s = off; s < off+dof; ++s) { 655 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr); 656 } 657 } 658 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 659 ierr = PetscViewerASCIIPrintf(viewer, "Cones:\n", name);CHKERRQ(ierr); 660 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);CHKERRQ(ierr); 661 for (p = pStart; p < pEnd; ++p) { 662 PetscInt dof, off, c; 663 664 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 665 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 666 for (c = off; c < off+dof; ++c) { 667 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr); 668 } 669 } 670 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 671 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 672 if (coordSection && coordinates) { 673 ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr); 674 } 675 ierr = DMGetLabel(dm, "marker", &markers);CHKERRQ(ierr); 676 if (markers) {ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);} 677 if (size > 1) { 678 PetscSF sf; 679 680 ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); 681 ierr = PetscSFView(sf, viewer);CHKERRQ(ierr); 682 } 683 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 684 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 685 const char *name, *color; 686 const char *defcolors[3] = {"gray", "orange", "green"}; 687 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 688 char lname[PETSC_MAX_PATH_LEN]; 689 PetscReal scale = 2.0; 690 PetscReal tikzscale = 1.0; 691 PetscBool useNumbers = PETSC_TRUE, useLabels, useColors; 692 double tcoords[3]; 693 PetscScalar *coords; 694 PetscInt numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p; 695 PetscMPIInt rank, size; 696 char **names, **colors, **lcolors; 697 PetscBool plotEdges, flg, lflg; 698 PetscBT wp = NULL; 699 PetscInt pEnd, pStart; 700 701 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 702 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 703 ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 704 numLabels = PetscMax(numLabels, 10); 705 numColors = 10; 706 numLColors = 10; 707 ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr); 708 ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr); 709 ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);CHKERRQ(ierr); 710 ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr); 711 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr); 712 if (!useLabels) numLabels = 0; 713 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr); 714 if (!useColors) { 715 numColors = 3; 716 for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);} 717 } 718 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr); 719 if (!useColors) { 720 numLColors = 4; 721 for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);} 722 } 723 ierr = PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, PETSC_MAX_PATH_LEN, &lflg);CHKERRQ(ierr); 724 plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3); 725 ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);CHKERRQ(ierr); 726 if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 727 if (depth < dim) plotEdges = PETSC_FALSE; 728 729 /* filter points with labelvalue != labeldefaultvalue */ 730 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 731 if (lflg) { 732 DMLabel lbl; 733 734 ierr = DMGetLabel(dm, lname, &lbl);CHKERRQ(ierr); 735 if (lbl) { 736 PetscInt val, defval; 737 738 ierr = DMLabelGetDefaultValue(lbl, &defval);CHKERRQ(ierr); 739 ierr = PetscBTCreate(pEnd-pStart, &wp);CHKERRQ(ierr); 740 for (c = pStart; c < pEnd; c++) { 741 PetscInt *closure = NULL; 742 PetscInt closureSize; 743 744 ierr = DMLabelGetValue(lbl, c, &val);CHKERRQ(ierr); 745 if (val == defval) continue; 746 747 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 748 for (p = 0; p < closureSize*2; p += 2) { 749 ierr = PetscBTSet(wp, closure[p] - pStart);CHKERRQ(ierr); 750 } 751 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 752 } 753 } 754 } 755 756 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr); 757 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr); 758 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 759 ierr = PetscViewerASCIIPrintf(viewer, "\ 760 \\documentclass[tikz]{standalone}\n\n\ 761 \\usepackage{pgflibraryshapes}\n\ 762 \\usetikzlibrary{backgrounds}\n\ 763 \\usetikzlibrary{arrows}\n\ 764 \\begin{document}\n");CHKERRQ(ierr); 765 if (size > 1) { 766 ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr); 767 for (p = 0; p < size; ++p) { 768 if (p > 0 && p == size-1) { 769 ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr); 770 } else if (p > 0) { 771 ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr); 772 } 773 ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr); 774 } 775 ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr); 776 } 777 ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);CHKERRQ(ierr); 778 779 /* Plot vertices */ 780 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 781 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 782 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 783 for (v = vStart; v < vEnd; ++v) { 784 PetscInt off, dof, d; 785 PetscBool isLabeled = PETSC_FALSE; 786 787 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 788 ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr); 789 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 790 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr); 791 if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof); 792 for (d = 0; d < dof; ++d) { 793 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 794 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 795 } 796 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 797 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 798 for (d = 0; d < dof; ++d) { 799 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 800 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);CHKERRQ(ierr); 801 } 802 color = colors[rank%numColors]; 803 for (l = 0; l < numLabels; ++l) { 804 PetscInt val; 805 ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr); 806 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 807 } 808 if (useNumbers) { 809 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr); 810 } else { 811 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr); 812 } 813 } 814 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 815 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 816 /* Plot cells */ 817 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 818 ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr); 819 if (dim == 3 || !useNumbers) { 820 for (e = eStart; e < eEnd; ++e) { 821 const PetscInt *cone; 822 823 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 824 color = colors[rank%numColors]; 825 for (l = 0; l < numLabels; ++l) { 826 PetscInt val; 827 ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr); 828 if (val >= 0) {color = lcolors[l%numLColors]; break;} 829 } 830 ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr); 831 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr); 832 } 833 } else { 834 for (c = cStart; c < cEnd; ++c) { 835 PetscInt *closure = NULL; 836 PetscInt closureSize, firstPoint = -1; 837 838 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 839 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 840 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr); 841 for (p = 0; p < closureSize*2; p += 2) { 842 const PetscInt point = closure[p]; 843 844 if ((point < vStart) || (point >= vEnd)) continue; 845 if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);} 846 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);CHKERRQ(ierr); 847 if (firstPoint < 0) firstPoint = point; 848 } 849 /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */ 850 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);CHKERRQ(ierr); 851 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 852 } 853 } 854 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 855 for (c = cStart; c < cEnd; ++c) { 856 double ccoords[3] = {0.0, 0.0, 0.0}; 857 PetscBool isLabeled = PETSC_FALSE; 858 PetscInt *closure = NULL; 859 PetscInt closureSize, dof, d, n = 0; 860 861 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 862 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 863 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr); 864 for (p = 0; p < closureSize*2; p += 2) { 865 const PetscInt point = closure[p]; 866 PetscInt off; 867 868 if ((point < vStart) || (point >= vEnd)) continue; 869 ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr); 870 ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr); 871 for (d = 0; d < dof; ++d) { 872 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 873 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 874 } 875 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 876 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 877 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 878 ++n; 879 } 880 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 881 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 882 for (d = 0; d < dof; ++d) { 883 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 884 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);CHKERRQ(ierr); 885 } 886 color = colors[rank%numColors]; 887 for (l = 0; l < numLabels; ++l) { 888 PetscInt val; 889 ierr = DMGetLabelValue(dm, names[l], c, &val);CHKERRQ(ierr); 890 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 891 } 892 if (useNumbers) { 893 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);CHKERRQ(ierr); 894 } else { 895 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr); 896 } 897 } 898 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 899 /* Plot edges */ 900 if (plotEdges) { 901 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 902 ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr); 903 for (e = eStart; e < eEnd; ++e) { 904 const PetscInt *cone; 905 PetscInt coneSize, offA, offB, dof, d; 906 907 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 908 ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr); 909 if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize); 910 ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr); 911 ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr); 912 ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr); 913 ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr); 914 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr); 915 for (d = 0; d < dof; ++d) { 916 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 917 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 918 } 919 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 920 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 921 for (d = 0; d < dof; ++d) { 922 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 923 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr); 924 } 925 color = colors[rank%numColors]; 926 for (l = 0; l < numLabels; ++l) { 927 PetscInt val; 928 ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr); 929 if (val >= 0) {color = lcolors[l%numLColors]; break;} 930 } 931 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr); 932 } 933 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 934 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 935 ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr); 936 } 937 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 938 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 939 ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr); 940 ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr); 941 for (l = 0; l < numLabels; ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);} 942 for (c = 0; c < numColors; ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);} 943 for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);} 944 ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr); 945 ierr = PetscBTDestroy(&wp);CHKERRQ(ierr); 946 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 947 Vec cown,acown; 948 VecScatter sct; 949 ISLocalToGlobalMapping g2l; 950 IS gid,acis; 951 MPI_Comm comm,ncomm = MPI_COMM_NULL; 952 MPI_Group ggroup,ngroup; 953 PetscScalar *array,nid; 954 const PetscInt *idxs; 955 PetscInt *idxs2,*start,*adjacency,*work; 956 PetscInt64 lm[3],gm[3]; 957 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 958 PetscMPIInt d1,d2,rank; 959 960 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 961 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 962 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 963 ierr = MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);CHKERRQ(ierr); 964 #endif 965 if (ncomm != MPI_COMM_NULL) { 966 ierr = MPI_Comm_group(comm,&ggroup);CHKERRQ(ierr); 967 ierr = MPI_Comm_group(ncomm,&ngroup);CHKERRQ(ierr); 968 d1 = 0; 969 ierr = MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);CHKERRQ(ierr); 970 nid = d2; 971 ierr = MPI_Group_free(&ggroup);CHKERRQ(ierr); 972 ierr = MPI_Group_free(&ngroup);CHKERRQ(ierr); 973 ierr = MPI_Comm_free(&ncomm);CHKERRQ(ierr); 974 } else nid = 0.0; 975 976 /* Get connectivity */ 977 ierr = DMPlexGetVTKCellHeight(dm,&cellHeight);CHKERRQ(ierr); 978 ierr = DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);CHKERRQ(ierr); 979 980 /* filter overlapped local cells */ 981 ierr = DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);CHKERRQ(ierr); 982 ierr = ISGetIndices(gid,&idxs);CHKERRQ(ierr); 983 ierr = ISGetLocalSize(gid,&cum);CHKERRQ(ierr); 984 ierr = PetscMalloc1(cum,&idxs2);CHKERRQ(ierr); 985 for (c = cStart, cum = 0; c < cEnd; c++) { 986 if (idxs[c-cStart] < 0) continue; 987 idxs2[cum++] = idxs[c-cStart]; 988 } 989 ierr = ISRestoreIndices(gid,&idxs);CHKERRQ(ierr); 990 if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum); 991 ierr = ISDestroy(&gid);CHKERRQ(ierr); 992 ierr = ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);CHKERRQ(ierr); 993 994 /* support for node-aware cell locality */ 995 ierr = ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);CHKERRQ(ierr); 996 ierr = VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);CHKERRQ(ierr); 997 ierr = VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);CHKERRQ(ierr); 998 ierr = VecGetArray(cown,&array);CHKERRQ(ierr); 999 for (c = 0; c < numVertices; c++) array[c] = nid; 1000 ierr = VecRestoreArray(cown,&array);CHKERRQ(ierr); 1001 ierr = VecScatterCreate(cown,acis,acown,NULL,&sct);CHKERRQ(ierr); 1002 ierr = VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1003 ierr = VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1004 ierr = ISDestroy(&acis);CHKERRQ(ierr); 1005 ierr = VecScatterDestroy(&sct);CHKERRQ(ierr); 1006 ierr = VecDestroy(&cown);CHKERRQ(ierr); 1007 1008 /* compute edgeCut */ 1009 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1010 ierr = PetscMalloc1(cum,&work);CHKERRQ(ierr); 1011 ierr = ISLocalToGlobalMappingCreateIS(gid,&g2l);CHKERRQ(ierr); 1012 ierr = ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr); 1013 ierr = ISDestroy(&gid);CHKERRQ(ierr); 1014 ierr = VecGetArray(acown,&array);CHKERRQ(ierr); 1015 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1016 PetscInt totl; 1017 1018 totl = start[c+1]-start[c]; 1019 ierr = ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);CHKERRQ(ierr); 1020 for (i = 0; i < totl; i++) { 1021 if (work[i] < 0) { 1022 ect += 1; 1023 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1024 } 1025 } 1026 } 1027 ierr = PetscFree(work);CHKERRQ(ierr); 1028 ierr = VecRestoreArray(acown,&array);CHKERRQ(ierr); 1029 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1030 lm[1] = -numVertices; 1031 ierr = MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);CHKERRQ(ierr); 1032 ierr = PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);CHKERRQ(ierr); 1033 lm[0] = ect; /* edgeCut */ 1034 lm[1] = ectn; /* node-aware edgeCut */ 1035 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1036 ierr = MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);CHKERRQ(ierr); 1037 ierr = PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);CHKERRQ(ierr); 1038 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1039 ierr = PetscViewerASCIIPrintf(viewer," Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.);CHKERRQ(ierr); 1040 #else 1041 ierr = PetscViewerASCIIPrintf(viewer," Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);CHKERRQ(ierr); 1042 #endif 1043 ierr = ISLocalToGlobalMappingDestroy(&g2l);CHKERRQ(ierr); 1044 ierr = PetscFree(start);CHKERRQ(ierr); 1045 ierr = PetscFree(adjacency);CHKERRQ(ierr); 1046 ierr = VecDestroy(&acown);CHKERRQ(ierr); 1047 } else { 1048 MPI_Comm comm; 1049 PetscInt *sizes, *hybsizes, *ghostsizes; 1050 PetscInt locDepth, depth, cellHeight, dim, d, pMax[4]; 1051 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1052 PetscInt numLabels, l; 1053 const char *name; 1054 PetscMPIInt size; 1055 1056 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 1057 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 1058 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1059 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 1060 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 1061 if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 1062 else {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 1063 if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);CHKERRQ(ierr);} 1064 ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr); 1065 ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 1066 ierr = DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);CHKERRQ(ierr); 1067 ierr = DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);CHKERRQ(ierr); 1068 gcNum = gcEnd - gcStart; 1069 ierr = PetscCalloc3(size,&sizes,size,&hybsizes,size,&ghostsizes);CHKERRQ(ierr); 1070 if (depth == 1) { 1071 ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr); 1072 pEnd = pEnd - pStart; 1073 pMax[0] -= pStart; 1074 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1075 ierr = MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1076 ierr = MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1077 ierr = PetscViewerASCIIPrintf(viewer, " %d-cells:", 0);CHKERRQ(ierr); 1078 for (p = 0; p < size; ++p) { 1079 if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);} 1080 else {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);} 1081 } 1082 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 1083 ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr); 1084 pEnd = pEnd - pStart; 1085 pMax[depth] -= pStart; 1086 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1087 ierr = MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1088 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);CHKERRQ(ierr); 1089 for (p = 0; p < size; ++p) { 1090 ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr); 1091 if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);CHKERRQ(ierr);} 1092 if (ghostsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);CHKERRQ(ierr);} 1093 } 1094 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 1095 } else { 1096 PetscMPIInt rank; 1097 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 1098 for (d = 0; d <= dim; d++) { 1099 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 1100 pEnd -= pStart; 1101 pMax[d] -= pStart; 1102 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1103 ierr = MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1104 if (d == dim) {ierr = MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);} 1105 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", d);CHKERRQ(ierr); 1106 for (p = 0; p < size; ++p) { 1107 if (!rank) { 1108 ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr); 1109 if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);CHKERRQ(ierr);} 1110 if (d == dim && ghostsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);CHKERRQ(ierr);} 1111 } 1112 } 1113 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 1114 } 1115 } 1116 ierr = PetscFree3(sizes,hybsizes,ghostsizes);CHKERRQ(ierr); 1117 ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 1118 if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);} 1119 for (l = 0; l < numLabels; ++l) { 1120 DMLabel label; 1121 const char *name; 1122 IS valueIS; 1123 const PetscInt *values; 1124 PetscInt numValues, v; 1125 1126 ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr); 1127 ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr); 1128 ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr); 1129 ierr = PetscViewerASCIIPrintf(viewer, " %s: %D strata with value/size (", name, numValues);CHKERRQ(ierr); 1130 ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr); 1131 ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr); 1132 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr); 1133 for (v = 0; v < numValues; ++v) { 1134 PetscInt size; 1135 1136 ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr); 1137 if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 1138 ierr = PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);CHKERRQ(ierr); 1139 } 1140 ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr); 1141 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr); 1142 ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr); 1143 ierr = ISDestroy(&valueIS);CHKERRQ(ierr); 1144 } 1145 /* If no fields are specified, people do not want to see adjacency */ 1146 if (dm->Nf) { 1147 PetscInt f; 1148 1149 for (f = 0; f < dm->Nf; ++f) { 1150 const char *name; 1151 1152 ierr = PetscObjectGetName(dm->fields[f].disc, &name);CHKERRQ(ierr); 1153 if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);CHKERRQ(ierr);} 1154 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 1155 if (dm->fields[f].label) {ierr = DMLabelView(dm->fields[f].label, viewer);CHKERRQ(ierr);} 1156 if (dm->fields[f].adjacency[0]) { 1157 if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");CHKERRQ(ierr);} 1158 else {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");CHKERRQ(ierr);} 1159 } else { 1160 if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");CHKERRQ(ierr);} 1161 else {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");CHKERRQ(ierr);} 1162 } 1163 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 1164 } 1165 } 1166 ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr); 1167 if (cdm) { 1168 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 1169 ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr); 1170 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 1171 } 1172 } 1173 PetscFunctionReturn(0); 1174 } 1175 1176 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1177 { 1178 PetscDraw draw; 1179 DM cdm; 1180 PetscSection coordSection; 1181 Vec coordinates; 1182 const PetscScalar *coords; 1183 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1184 PetscBool isnull; 1185 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N; 1186 PetscMPIInt rank; 1187 PetscErrorCode ierr; 1188 1189 PetscFunctionBegin; 1190 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 1191 if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim); 1192 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 1193 ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr); 1194 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1195 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1196 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 1197 1198 ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr); 1199 ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr); 1200 if (isnull) PetscFunctionReturn(0); 1201 ierr = PetscDrawSetTitle(draw, "Mesh");CHKERRQ(ierr); 1202 1203 ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); 1204 ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); 1205 for (c = 0; c < N; c += dim) { 1206 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1207 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1208 } 1209 ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); 1210 ierr = MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 1211 ierr = MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 1212 ierr = PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);CHKERRQ(ierr); 1213 ierr = PetscDrawClear(draw);CHKERRQ(ierr); 1214 1215 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr); 1216 for (c = cStart; c < cEnd; ++c) { 1217 PetscScalar *coords = NULL; 1218 DMPolytopeType ct; 1219 PetscInt numCoords; 1220 1221 ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr); 1222 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 1223 switch (ct) { 1224 case DM_POLYTOPE_TRIANGLE: 1225 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1226 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1227 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1228 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr); 1229 break; 1230 case DM_POLYTOPE_QUADRILATERAL: 1231 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1232 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1233 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1234 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr); 1235 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1236 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1237 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1238 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr); 1239 break; 1240 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1241 } 1242 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 1243 } 1244 for (c = cStart; c < cEnd; ++c) { 1245 PetscScalar *coords = NULL; 1246 DMPolytopeType ct; 1247 PetscInt numCoords; 1248 1249 ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr); 1250 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 1251 switch (ct) { 1252 case DM_POLYTOPE_TRIANGLE: 1253 ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1254 ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1255 ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1256 break; 1257 case DM_POLYTOPE_QUADRILATERAL: 1258 ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1259 ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1260 ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1261 ierr = PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1262 break; 1263 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1264 } 1265 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 1266 } 1267 ierr = PetscDrawFlush(draw);CHKERRQ(ierr); 1268 ierr = PetscDrawPause(draw);CHKERRQ(ierr); 1269 ierr = PetscDrawSave(draw);CHKERRQ(ierr); 1270 PetscFunctionReturn(0); 1271 } 1272 1273 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1274 { 1275 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis; 1276 char name[PETSC_MAX_PATH_LEN]; 1277 PetscErrorCode ierr; 1278 1279 PetscFunctionBegin; 1280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1281 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1282 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 1283 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 1284 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1285 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 1286 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr); 1287 if (iascii) { 1288 PetscViewerFormat format; 1289 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1290 if (format == PETSC_VIEWER_ASCII_GLVIS) { 1291 ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr); 1292 } else { 1293 ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr); 1294 } 1295 } else if (ishdf5) { 1296 #if defined(PETSC_HAVE_HDF5) 1297 ierr = DMPlexView_HDF5_Internal(dm, viewer);CHKERRQ(ierr); 1298 #else 1299 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1300 #endif 1301 } else if (isvtk) { 1302 ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr); 1303 } else if (isdraw) { 1304 ierr = DMPlexView_Draw(dm, viewer);CHKERRQ(ierr); 1305 } else if (isglvis) { 1306 ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr); 1307 } else { 1308 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1309 } 1310 /* Optionally view the partition */ 1311 ierr = PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);CHKERRQ(ierr); 1312 if (flg) { 1313 Vec ranks; 1314 ierr = DMPlexCreateRankField(dm, &ranks);CHKERRQ(ierr); 1315 ierr = VecView(ranks, viewer);CHKERRQ(ierr); 1316 ierr = VecDestroy(&ranks);CHKERRQ(ierr); 1317 } 1318 /* Optionally view a label */ 1319 ierr = PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, PETSC_MAX_PATH_LEN, &flg);CHKERRQ(ierr); 1320 if (flg) { 1321 DMLabel label; 1322 Vec val; 1323 1324 ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr); 1325 if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1326 ierr = DMPlexCreateLabelField(dm, label, &val);CHKERRQ(ierr); 1327 ierr = VecView(val, viewer);CHKERRQ(ierr); 1328 ierr = VecDestroy(&val);CHKERRQ(ierr); 1329 } 1330 PetscFunctionReturn(0); 1331 } 1332 1333 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 1334 { 1335 PetscBool ishdf5; 1336 PetscErrorCode ierr; 1337 1338 PetscFunctionBegin; 1339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1340 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1341 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1342 if (ishdf5) { 1343 #if defined(PETSC_HAVE_HDF5) 1344 PetscViewerFormat format; 1345 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1346 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 1347 ierr = DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);CHKERRQ(ierr); 1348 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1349 ierr = DMPlexLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr); 1350 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1351 #else 1352 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1353 #endif 1354 } else { 1355 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 1356 } 1357 PetscFunctionReturn(0); 1358 } 1359 1360 PetscErrorCode DMDestroy_Plex(DM dm) 1361 { 1362 DM_Plex *mesh = (DM_Plex*) dm->data; 1363 PetscErrorCode ierr; 1364 1365 PetscFunctionBegin; 1366 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);CHKERRQ(ierr); 1367 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);CHKERRQ(ierr); 1368 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);CHKERRQ(ierr); 1369 if (--mesh->refct > 0) PetscFunctionReturn(0); 1370 ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr); 1371 ierr = PetscFree(mesh->cones);CHKERRQ(ierr); 1372 ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr); 1373 ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr); 1374 ierr = PetscSectionDestroy(&mesh->subdomainSection);CHKERRQ(ierr); 1375 ierr = PetscFree(mesh->supports);CHKERRQ(ierr); 1376 ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr); 1377 ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr); 1378 ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr); 1379 ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr); 1380 ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr); 1381 ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr); 1382 ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr); 1383 ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr); 1384 ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr); 1385 ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr); 1386 ierr = PetscFree(mesh->parents);CHKERRQ(ierr); 1387 ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr); 1388 ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr); 1389 ierr = PetscFree(mesh->children);CHKERRQ(ierr); 1390 ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr); 1391 ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr); 1392 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 1393 ierr = PetscFree(mesh);CHKERRQ(ierr); 1394 PetscFunctionReturn(0); 1395 } 1396 1397 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 1398 { 1399 PetscSection sectionGlobal; 1400 PetscInt bs = -1, mbs; 1401 PetscInt localSize; 1402 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 1403 PetscErrorCode ierr; 1404 MatType mtype; 1405 ISLocalToGlobalMapping ltog; 1406 1407 PetscFunctionBegin; 1408 ierr = MatInitializePackage();CHKERRQ(ierr); 1409 mtype = dm->mattype; 1410 ierr = DMGetGlobalSection(dm, §ionGlobal);CHKERRQ(ierr); 1411 /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */ 1412 ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); 1413 ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr); 1414 ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 1415 ierr = MatSetType(*J, mtype);CHKERRQ(ierr); 1416 ierr = MatSetFromOptions(*J);CHKERRQ(ierr); 1417 ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr); 1418 if (mbs > 1) bs = mbs; 1419 ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr); 1420 ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr); 1421 ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr); 1422 ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr); 1423 ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr); 1424 ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr); 1425 ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr); 1426 ierr = PetscStrcmp(mtype, MATIS, &isMatIS);CHKERRQ(ierr); 1427 if (!isShell) { 1428 PetscSection subSection; 1429 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 1430 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize; 1431 PetscInt pStart, pEnd, p, dof, cdof; 1432 1433 /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */ 1434 if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */ 1435 PetscSection section; 1436 PetscInt size; 1437 1438 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 1439 ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr); 1440 ierr = PetscMalloc1(size,<ogidx);CHKERRQ(ierr); 1441 ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr); 1442 } else { 1443 ierr = DMGetLocalToGlobalMapping(dm,<og);CHKERRQ(ierr); 1444 } 1445 ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr); 1446 for (p = pStart, lsize = 0; p < pEnd; ++p) { 1447 PetscInt bdof; 1448 1449 ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr); 1450 ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr); 1451 dof = dof < 0 ? -(dof+1) : dof; 1452 bdof = cdof && (dof-cdof) ? 1 : dof; 1453 if (dof) { 1454 if (bs < 0) {bs = bdof;} 1455 else if (bs != bdof) {bs = 1; if (!isMatIS) break;} 1456 } 1457 if (isMatIS) { 1458 PetscInt loff,c,off; 1459 ierr = PetscSectionGetOffset(subSection, p, &loff);CHKERRQ(ierr); 1460 ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr); 1461 for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c; 1462 } 1463 } 1464 /* Must have same blocksize on all procs (some might have no points) */ 1465 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 1466 ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr); 1467 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 1468 else {bs = bsMinMax[0];} 1469 bs = PetscMax(1,bs); 1470 if (isMatIS) { /* Must reduce indices by blocksize */ 1471 PetscInt l; 1472 1473 lsize = lsize/bs; 1474 if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs; 1475 ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, <og);CHKERRQ(ierr); 1476 } 1477 ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr); 1478 if (isMatIS) { 1479 ierr = ISLocalToGlobalMappingDestroy(<og);CHKERRQ(ierr); 1480 } 1481 ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr); 1482 ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr); 1483 ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr); 1484 } 1485 ierr = MatSetDM(*J, dm);CHKERRQ(ierr); 1486 PetscFunctionReturn(0); 1487 } 1488 1489 /*@ 1490 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 1491 1492 Not collective 1493 1494 Input Parameter: 1495 . mesh - The DMPlex 1496 1497 Output Parameters: 1498 . subsection - The subdomain section 1499 1500 Level: developer 1501 1502 .seealso: 1503 @*/ 1504 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 1505 { 1506 DM_Plex *mesh = (DM_Plex*) dm->data; 1507 PetscErrorCode ierr; 1508 1509 PetscFunctionBegin; 1510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1511 if (!mesh->subdomainSection) { 1512 PetscSection section; 1513 PetscSF sf; 1514 1515 ierr = PetscSFCreate(PETSC_COMM_SELF,&sf);CHKERRQ(ierr); 1516 ierr = DMGetLocalSection(dm,§ion);CHKERRQ(ierr); 1517 ierr = PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);CHKERRQ(ierr); 1518 ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); 1519 } 1520 *subsection = mesh->subdomainSection; 1521 PetscFunctionReturn(0); 1522 } 1523 1524 /*@ 1525 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 1526 1527 Not collective 1528 1529 Input Parameter: 1530 . mesh - The DMPlex 1531 1532 Output Parameters: 1533 + pStart - The first mesh point 1534 - pEnd - The upper bound for mesh points 1535 1536 Level: beginner 1537 1538 .seealso: DMPlexCreate(), DMPlexSetChart() 1539 @*/ 1540 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 1541 { 1542 DM_Plex *mesh = (DM_Plex*) dm->data; 1543 PetscErrorCode ierr; 1544 1545 PetscFunctionBegin; 1546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1547 ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 1548 PetscFunctionReturn(0); 1549 } 1550 1551 /*@ 1552 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 1553 1554 Not collective 1555 1556 Input Parameters: 1557 + mesh - The DMPlex 1558 . pStart - The first mesh point 1559 - pEnd - The upper bound for mesh points 1560 1561 Output Parameters: 1562 1563 Level: beginner 1564 1565 .seealso: DMPlexCreate(), DMPlexGetChart() 1566 @*/ 1567 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 1568 { 1569 DM_Plex *mesh = (DM_Plex*) dm->data; 1570 PetscErrorCode ierr; 1571 1572 PetscFunctionBegin; 1573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1574 ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 1575 ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr); 1576 PetscFunctionReturn(0); 1577 } 1578 1579 /*@ 1580 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 1581 1582 Not collective 1583 1584 Input Parameters: 1585 + mesh - The DMPlex 1586 - p - The point, which must lie in the chart set with DMPlexSetChart() 1587 1588 Output Parameter: 1589 . size - The cone size for point p 1590 1591 Level: beginner 1592 1593 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 1594 @*/ 1595 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 1596 { 1597 DM_Plex *mesh = (DM_Plex*) dm->data; 1598 PetscErrorCode ierr; 1599 1600 PetscFunctionBegin; 1601 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1602 PetscValidPointer(size, 3); 1603 ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 1604 PetscFunctionReturn(0); 1605 } 1606 1607 /*@ 1608 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 1609 1610 Not collective 1611 1612 Input Parameters: 1613 + mesh - The DMPlex 1614 . p - The point, which must lie in the chart set with DMPlexSetChart() 1615 - size - The cone size for point p 1616 1617 Output Parameter: 1618 1619 Note: 1620 This should be called after DMPlexSetChart(). 1621 1622 Level: beginner 1623 1624 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart() 1625 @*/ 1626 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 1627 { 1628 DM_Plex *mesh = (DM_Plex*) dm->data; 1629 PetscErrorCode ierr; 1630 1631 PetscFunctionBegin; 1632 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1633 ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 1634 1635 mesh->maxConeSize = PetscMax(mesh->maxConeSize, size); 1636 PetscFunctionReturn(0); 1637 } 1638 1639 /*@ 1640 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 1641 1642 Not collective 1643 1644 Input Parameters: 1645 + mesh - The DMPlex 1646 . p - The point, which must lie in the chart set with DMPlexSetChart() 1647 - size - The additional cone size for point p 1648 1649 Output Parameter: 1650 1651 Note: 1652 This should be called after DMPlexSetChart(). 1653 1654 Level: beginner 1655 1656 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart() 1657 @*/ 1658 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 1659 { 1660 DM_Plex *mesh = (DM_Plex*) dm->data; 1661 PetscInt csize; 1662 PetscErrorCode ierr; 1663 1664 PetscFunctionBegin; 1665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1666 ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr); 1667 ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr); 1668 1669 mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize); 1670 PetscFunctionReturn(0); 1671 } 1672 1673 /*@C 1674 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 1675 1676 Not collective 1677 1678 Input Parameters: 1679 + dm - The DMPlex 1680 - p - The point, which must lie in the chart set with DMPlexSetChart() 1681 1682 Output Parameter: 1683 . cone - An array of points which are on the in-edges for point p 1684 1685 Level: beginner 1686 1687 Fortran Notes: 1688 Since it returns an array, this routine is only available in Fortran 90, and you must 1689 include petsc.h90 in your code. 1690 You must also call DMPlexRestoreCone() after you finish using the returned array. 1691 DMPlexRestoreCone() is not needed/available in C. 1692 1693 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart() 1694 @*/ 1695 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 1696 { 1697 DM_Plex *mesh = (DM_Plex*) dm->data; 1698 PetscInt off; 1699 PetscErrorCode ierr; 1700 1701 PetscFunctionBegin; 1702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1703 PetscValidPointer(cone, 3); 1704 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1705 *cone = &mesh->cones[off]; 1706 PetscFunctionReturn(0); 1707 } 1708 1709 /*@C 1710 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 1711 1712 Not collective 1713 1714 Input Parameters: 1715 + dm - The DMPlex 1716 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 1717 1718 Output Parameter: 1719 + pConesSection - PetscSection describing the layout of pCones 1720 - pCones - An array of points which are on the in-edges for the point set p 1721 1722 Level: intermediate 1723 1724 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart() 1725 @*/ 1726 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 1727 { 1728 PetscSection cs, newcs; 1729 PetscInt *cones; 1730 PetscInt *newarr=NULL; 1731 PetscInt n; 1732 PetscErrorCode ierr; 1733 1734 PetscFunctionBegin; 1735 ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr); 1736 ierr = DMPlexGetConeSection(dm, &cs);CHKERRQ(ierr); 1737 ierr = PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);CHKERRQ(ierr); 1738 if (pConesSection) *pConesSection = newcs; 1739 if (pCones) { 1740 ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr); 1741 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);CHKERRQ(ierr); 1742 } 1743 PetscFunctionReturn(0); 1744 } 1745 1746 /*@ 1747 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 1748 1749 Not collective 1750 1751 Input Parameters: 1752 + dm - The DMPlex 1753 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 1754 1755 Output Parameter: 1756 . expandedPoints - An array of vertices recursively expanded from input points 1757 1758 Level: advanced 1759 1760 Notes: 1761 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 1762 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 1763 1764 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth() 1765 @*/ 1766 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 1767 { 1768 IS *expandedPointsAll; 1769 PetscInt depth; 1770 PetscErrorCode ierr; 1771 1772 PetscFunctionBegin; 1773 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1774 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 1775 PetscValidPointer(expandedPoints, 3); 1776 ierr = DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr); 1777 *expandedPoints = expandedPointsAll[0]; 1778 ierr = PetscObjectReference((PetscObject)expandedPointsAll[0]); 1779 ierr = DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr); 1780 PetscFunctionReturn(0); 1781 } 1782 1783 /*@ 1784 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 1785 1786 Not collective 1787 1788 Input Parameters: 1789 + dm - The DMPlex 1790 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 1791 1792 Output Parameter: 1793 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 1794 . expandedPoints - (optional) An array of index sets with recursively expanded cones 1795 - sections - (optional) An array of sections which describe mappings from points to their cone points 1796 1797 Level: advanced 1798 1799 Notes: 1800 Like DMPlexGetConeTuple() but recursive. 1801 1802 Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 1803 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 1804 1805 Array section has size equal to depth. Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows: 1806 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 1807 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 1808 1809 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 1810 @*/ 1811 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 1812 { 1813 const PetscInt *arr0=NULL, *cone=NULL; 1814 PetscInt *arr=NULL, *newarr=NULL; 1815 PetscInt d, depth_, i, n, newn, cn, co, start, end; 1816 IS *expandedPoints_; 1817 PetscSection *sections_; 1818 PetscErrorCode ierr; 1819 1820 PetscFunctionBegin; 1821 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1822 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 1823 if (depth) PetscValidIntPointer(depth, 3); 1824 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 1825 if (sections) PetscValidPointer(sections, 5); 1826 ierr = ISGetLocalSize(points, &n);CHKERRQ(ierr); 1827 ierr = ISGetIndices(points, &arr0);CHKERRQ(ierr); 1828 ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr); 1829 ierr = PetscCalloc1(depth_, &expandedPoints_);CHKERRQ(ierr); 1830 ierr = PetscCalloc1(depth_, §ions_);CHKERRQ(ierr); 1831 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 1832 for (d=depth_-1; d>=0; d--) { 1833 ierr = PetscSectionCreate(PETSC_COMM_SELF, §ions_[d]);CHKERRQ(ierr); 1834 ierr = PetscSectionSetChart(sections_[d], 0, n);CHKERRQ(ierr); 1835 for (i=0; i<n; i++) { 1836 ierr = DMPlexGetDepthStratum(dm, d+1, &start, &end);CHKERRQ(ierr); 1837 if (arr[i] >= start && arr[i] < end) { 1838 ierr = DMPlexGetConeSize(dm, arr[i], &cn);CHKERRQ(ierr); 1839 ierr = PetscSectionSetDof(sections_[d], i, cn);CHKERRQ(ierr); 1840 } else { 1841 ierr = PetscSectionSetDof(sections_[d], i, 1);CHKERRQ(ierr); 1842 } 1843 } 1844 ierr = PetscSectionSetUp(sections_[d]);CHKERRQ(ierr); 1845 ierr = PetscSectionGetStorageSize(sections_[d], &newn);CHKERRQ(ierr); 1846 ierr = PetscMalloc1(newn, &newarr);CHKERRQ(ierr); 1847 for (i=0; i<n; i++) { 1848 ierr = PetscSectionGetDof(sections_[d], i, &cn);CHKERRQ(ierr); 1849 ierr = PetscSectionGetOffset(sections_[d], i, &co);CHKERRQ(ierr); 1850 if (cn > 1) { 1851 ierr = DMPlexGetCone(dm, arr[i], &cone);CHKERRQ(ierr); 1852 ierr = PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));CHKERRQ(ierr); 1853 } else { 1854 newarr[co] = arr[i]; 1855 } 1856 } 1857 ierr = ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);CHKERRQ(ierr); 1858 arr = newarr; 1859 n = newn; 1860 } 1861 ierr = ISRestoreIndices(points, &arr0);CHKERRQ(ierr); 1862 *depth = depth_; 1863 if (expandedPoints) *expandedPoints = expandedPoints_; 1864 else { 1865 for (d=0; d<depth_; d++) {ierr = ISDestroy(&expandedPoints_[d]);CHKERRQ(ierr);} 1866 ierr = PetscFree(expandedPoints_);CHKERRQ(ierr); 1867 } 1868 if (sections) *sections = sections_; 1869 else { 1870 for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(§ions_[d]);CHKERRQ(ierr);} 1871 ierr = PetscFree(sections_);CHKERRQ(ierr); 1872 } 1873 PetscFunctionReturn(0); 1874 } 1875 1876 /*@ 1877 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 1878 1879 Not collective 1880 1881 Input Parameters: 1882 + dm - The DMPlex 1883 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 1884 1885 Output Parameter: 1886 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 1887 . expandedPoints - (optional) An array of recursively expanded cones 1888 - sections - (optional) An array of sections which describe mappings from points to their cone points 1889 1890 Level: advanced 1891 1892 Notes: 1893 See DMPlexGetConeRecursive() for details. 1894 1895 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 1896 @*/ 1897 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 1898 { 1899 PetscInt d, depth_; 1900 PetscErrorCode ierr; 1901 1902 PetscFunctionBegin; 1903 ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr); 1904 if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 1905 if (depth) *depth = 0; 1906 if (expandedPoints) { 1907 for (d=0; d<depth_; d++) {ierr = ISDestroy(&((*expandedPoints)[d]));CHKERRQ(ierr);} 1908 ierr = PetscFree(*expandedPoints);CHKERRQ(ierr); 1909 } 1910 if (sections) { 1911 for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&((*sections)[d]));CHKERRQ(ierr);} 1912 ierr = PetscFree(*sections);CHKERRQ(ierr); 1913 } 1914 PetscFunctionReturn(0); 1915 } 1916 1917 /*@ 1918 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 1919 1920 Not collective 1921 1922 Input Parameters: 1923 + mesh - The DMPlex 1924 . p - The point, which must lie in the chart set with DMPlexSetChart() 1925 - cone - An array of points which are on the in-edges for point p 1926 1927 Output Parameter: 1928 1929 Note: 1930 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 1931 1932 Developer Note: Why not call this DMPlexSetCover() 1933 1934 Level: beginner 1935 1936 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize() 1937 @*/ 1938 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 1939 { 1940 DM_Plex *mesh = (DM_Plex*) dm->data; 1941 PetscInt pStart, pEnd; 1942 PetscInt dof, off, c; 1943 PetscErrorCode ierr; 1944 1945 PetscFunctionBegin; 1946 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1947 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 1948 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1949 if (dof) PetscValidPointer(cone, 3); 1950 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1951 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); 1952 for (c = 0; c < dof; ++c) { 1953 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); 1954 mesh->cones[off+c] = cone[c]; 1955 } 1956 PetscFunctionReturn(0); 1957 } 1958 1959 /*@C 1960 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 1961 1962 Not collective 1963 1964 Input Parameters: 1965 + mesh - The DMPlex 1966 - p - The point, which must lie in the chart set with DMPlexSetChart() 1967 1968 Output Parameter: 1969 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 1970 integer giving the prescription for cone traversal. If it is negative, the cone is 1971 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 1972 the index of the cone point on which to start. 1973 1974 Level: beginner 1975 1976 Fortran Notes: 1977 Since it returns an array, this routine is only available in Fortran 90, and you must 1978 include petsc.h90 in your code. 1979 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 1980 DMPlexRestoreConeOrientation() is not needed/available in C. 1981 1982 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart() 1983 @*/ 1984 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 1985 { 1986 DM_Plex *mesh = (DM_Plex*) dm->data; 1987 PetscInt off; 1988 PetscErrorCode ierr; 1989 1990 PetscFunctionBegin; 1991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1992 #if defined(PETSC_USE_DEBUG) 1993 { 1994 PetscInt dof; 1995 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1996 if (dof) PetscValidPointer(coneOrientation, 3); 1997 } 1998 #endif 1999 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2000 2001 *coneOrientation = &mesh->coneOrientations[off]; 2002 PetscFunctionReturn(0); 2003 } 2004 2005 /*@ 2006 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 2007 2008 Not collective 2009 2010 Input Parameters: 2011 + mesh - The DMPlex 2012 . p - The point, which must lie in the chart set with DMPlexSetChart() 2013 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 2014 integer giving the prescription for cone traversal. If it is negative, the cone is 2015 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 2016 the index of the cone point on which to start. 2017 2018 Output Parameter: 2019 2020 Note: 2021 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2022 2023 Level: beginner 2024 2025 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2026 @*/ 2027 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 2028 { 2029 DM_Plex *mesh = (DM_Plex*) dm->data; 2030 PetscInt pStart, pEnd; 2031 PetscInt dof, off, c; 2032 PetscErrorCode ierr; 2033 2034 PetscFunctionBegin; 2035 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2036 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2037 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2038 if (dof) PetscValidPointer(coneOrientation, 3); 2039 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2040 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); 2041 for (c = 0; c < dof; ++c) { 2042 PetscInt cdof, o = coneOrientation[c]; 2043 2044 ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr); 2045 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); 2046 mesh->coneOrientations[off+c] = o; 2047 } 2048 PetscFunctionReturn(0); 2049 } 2050 2051 /*@ 2052 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 2053 2054 Not collective 2055 2056 Input Parameters: 2057 + mesh - The DMPlex 2058 . p - The point, which must lie in the chart set with DMPlexSetChart() 2059 . conePos - The local index in the cone where the point should be put 2060 - conePoint - The mesh point to insert 2061 2062 Level: beginner 2063 2064 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2065 @*/ 2066 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 2067 { 2068 DM_Plex *mesh = (DM_Plex*) dm->data; 2069 PetscInt pStart, pEnd; 2070 PetscInt dof, off; 2071 PetscErrorCode ierr; 2072 2073 PetscFunctionBegin; 2074 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2075 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2076 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); 2077 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); 2078 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2079 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2080 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); 2081 mesh->cones[off+conePos] = conePoint; 2082 PetscFunctionReturn(0); 2083 } 2084 2085 /*@ 2086 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 2087 2088 Not collective 2089 2090 Input Parameters: 2091 + mesh - The DMPlex 2092 . p - The point, which must lie in the chart set with DMPlexSetChart() 2093 . conePos - The local index in the cone where the point should be put 2094 - coneOrientation - The point orientation to insert 2095 2096 Level: beginner 2097 2098 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2099 @*/ 2100 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 2101 { 2102 DM_Plex *mesh = (DM_Plex*) dm->data; 2103 PetscInt pStart, pEnd; 2104 PetscInt dof, off; 2105 PetscErrorCode ierr; 2106 2107 PetscFunctionBegin; 2108 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2109 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2110 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); 2111 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2112 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2113 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); 2114 mesh->coneOrientations[off+conePos] = coneOrientation; 2115 PetscFunctionReturn(0); 2116 } 2117 2118 /*@ 2119 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 2120 2121 Not collective 2122 2123 Input Parameters: 2124 + mesh - The DMPlex 2125 - p - The point, which must lie in the chart set with DMPlexSetChart() 2126 2127 Output Parameter: 2128 . size - The support size for point p 2129 2130 Level: beginner 2131 2132 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize() 2133 @*/ 2134 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 2135 { 2136 DM_Plex *mesh = (DM_Plex*) dm->data; 2137 PetscErrorCode ierr; 2138 2139 PetscFunctionBegin; 2140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2141 PetscValidPointer(size, 3); 2142 ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 2143 PetscFunctionReturn(0); 2144 } 2145 2146 /*@ 2147 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 2148 2149 Not collective 2150 2151 Input Parameters: 2152 + mesh - The DMPlex 2153 . p - The point, which must lie in the chart set with DMPlexSetChart() 2154 - size - The support size for point p 2155 2156 Output Parameter: 2157 2158 Note: 2159 This should be called after DMPlexSetChart(). 2160 2161 Level: beginner 2162 2163 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart() 2164 @*/ 2165 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 2166 { 2167 DM_Plex *mesh = (DM_Plex*) dm->data; 2168 PetscErrorCode ierr; 2169 2170 PetscFunctionBegin; 2171 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2172 ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 2173 2174 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size); 2175 PetscFunctionReturn(0); 2176 } 2177 2178 /*@C 2179 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 2180 2181 Not collective 2182 2183 Input Parameters: 2184 + mesh - The DMPlex 2185 - p - The point, which must lie in the chart set with DMPlexSetChart() 2186 2187 Output Parameter: 2188 . support - An array of points which are on the out-edges for point p 2189 2190 Level: beginner 2191 2192 Fortran Notes: 2193 Since it returns an array, this routine is only available in Fortran 90, and you must 2194 include petsc.h90 in your code. 2195 You must also call DMPlexRestoreSupport() after you finish using the returned array. 2196 DMPlexRestoreSupport() is not needed/available in C. 2197 2198 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 2199 @*/ 2200 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 2201 { 2202 DM_Plex *mesh = (DM_Plex*) dm->data; 2203 PetscInt off; 2204 PetscErrorCode ierr; 2205 2206 PetscFunctionBegin; 2207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2208 PetscValidPointer(support, 3); 2209 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 2210 *support = &mesh->supports[off]; 2211 PetscFunctionReturn(0); 2212 } 2213 2214 /*@ 2215 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 2216 2217 Not collective 2218 2219 Input Parameters: 2220 + mesh - The DMPlex 2221 . p - The point, which must lie in the chart set with DMPlexSetChart() 2222 - support - An array of points which are on the out-edges for point p 2223 2224 Output Parameter: 2225 2226 Note: 2227 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 2228 2229 Level: beginner 2230 2231 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp() 2232 @*/ 2233 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 2234 { 2235 DM_Plex *mesh = (DM_Plex*) dm->data; 2236 PetscInt pStart, pEnd; 2237 PetscInt dof, off, c; 2238 PetscErrorCode ierr; 2239 2240 PetscFunctionBegin; 2241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2242 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 2243 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 2244 if (dof) PetscValidPointer(support, 3); 2245 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 2246 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); 2247 for (c = 0; c < dof; ++c) { 2248 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); 2249 mesh->supports[off+c] = support[c]; 2250 } 2251 PetscFunctionReturn(0); 2252 } 2253 2254 /*@ 2255 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 2256 2257 Not collective 2258 2259 Input Parameters: 2260 + mesh - The DMPlex 2261 . p - The point, which must lie in the chart set with DMPlexSetChart() 2262 . supportPos - The local index in the cone where the point should be put 2263 - supportPoint - The mesh point to insert 2264 2265 Level: beginner 2266 2267 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2268 @*/ 2269 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 2270 { 2271 DM_Plex *mesh = (DM_Plex*) dm->data; 2272 PetscInt pStart, pEnd; 2273 PetscInt dof, off; 2274 PetscErrorCode ierr; 2275 2276 PetscFunctionBegin; 2277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2278 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 2279 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 2280 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 2281 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); 2282 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); 2283 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); 2284 mesh->supports[off+supportPos] = supportPoint; 2285 PetscFunctionReturn(0); 2286 } 2287 2288 /*@C 2289 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 2290 2291 Not collective 2292 2293 Input Parameters: 2294 + mesh - The DMPlex 2295 . p - The point, which must lie in the chart set with DMPlexSetChart() 2296 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 2297 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 2298 2299 Output Parameters: 2300 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 2301 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 2302 2303 Note: 2304 If using internal storage (points is NULL on input), each call overwrites the last output. 2305 2306 Fortran Notes: 2307 Since it returns an array, this routine is only available in Fortran 90, and you must 2308 include petsc.h90 in your code. 2309 2310 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2311 2312 Level: beginner 2313 2314 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 2315 @*/ 2316 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 2317 { 2318 DM_Plex *mesh = (DM_Plex*) dm->data; 2319 PetscInt *closure, *fifo; 2320 const PetscInt *tmp = NULL, *tmpO = NULL; 2321 PetscInt tmpSize, t; 2322 PetscInt depth = 0, maxSize; 2323 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 2324 PetscErrorCode ierr; 2325 2326 PetscFunctionBegin; 2327 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2328 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 2329 /* This is only 1-level */ 2330 if (useCone) { 2331 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 2332 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 2333 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 2334 } else { 2335 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 2336 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 2337 } 2338 if (depth == 1) { 2339 if (*points) { 2340 closure = *points; 2341 } else { 2342 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 2343 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2344 } 2345 closure[0] = p; closure[1] = 0; 2346 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 2347 closure[closureSize] = tmp[t]; 2348 closure[closureSize+1] = tmpO ? tmpO[t] : 0; 2349 } 2350 if (numPoints) *numPoints = closureSize/2; 2351 if (points) *points = closure; 2352 PetscFunctionReturn(0); 2353 } 2354 { 2355 PetscInt c, coneSeries, s,supportSeries; 2356 2357 c = mesh->maxConeSize; 2358 coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1; 2359 s = mesh->maxSupportSize; 2360 supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1; 2361 maxSize = 2*PetscMax(coneSeries,supportSeries); 2362 } 2363 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 2364 if (*points) { 2365 closure = *points; 2366 } else { 2367 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2368 } 2369 closure[0] = p; closure[1] = 0; 2370 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 2371 const PetscInt cp = tmp[t]; 2372 const PetscInt co = tmpO ? tmpO[t] : 0; 2373 2374 closure[closureSize] = cp; 2375 closure[closureSize+1] = co; 2376 fifo[fifoSize] = cp; 2377 fifo[fifoSize+1] = co; 2378 } 2379 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 2380 while (fifoSize - fifoStart) { 2381 const PetscInt q = fifo[fifoStart]; 2382 const PetscInt o = fifo[fifoStart+1]; 2383 const PetscInt rev = o >= 0 ? 0 : 1; 2384 const PetscInt off = rev ? -(o+1) : o; 2385 2386 if (useCone) { 2387 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 2388 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 2389 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 2390 } else { 2391 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 2392 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 2393 tmpO = NULL; 2394 } 2395 for (t = 0; t < tmpSize; ++t) { 2396 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 2397 const PetscInt cp = tmp[i]; 2398 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 2399 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 2400 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 2401 PetscInt co = tmpO ? tmpO[i] : 0; 2402 PetscInt c; 2403 2404 if (rev) { 2405 PetscInt childSize, coff; 2406 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 2407 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 2408 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 2409 } 2410 /* Check for duplicate */ 2411 for (c = 0; c < closureSize; c += 2) { 2412 if (closure[c] == cp) break; 2413 } 2414 if (c == closureSize) { 2415 closure[closureSize] = cp; 2416 closure[closureSize+1] = co; 2417 fifo[fifoSize] = cp; 2418 fifo[fifoSize+1] = co; 2419 closureSize += 2; 2420 fifoSize += 2; 2421 } 2422 } 2423 fifoStart += 2; 2424 } 2425 if (numPoints) *numPoints = closureSize/2; 2426 if (points) *points = closure; 2427 ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 2428 PetscFunctionReturn(0); 2429 } 2430 2431 /*@C 2432 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 2433 2434 Not collective 2435 2436 Input Parameters: 2437 + mesh - The DMPlex 2438 . p - The point, which must lie in the chart set with DMPlexSetChart() 2439 . orientation - The orientation of the point 2440 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 2441 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 2442 2443 Output Parameters: 2444 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 2445 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 2446 2447 Note: 2448 If using internal storage (points is NULL on input), each call overwrites the last output. 2449 2450 Fortran Notes: 2451 Since it returns an array, this routine is only available in Fortran 90, and you must 2452 include petsc.h90 in your code. 2453 2454 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2455 2456 Level: beginner 2457 2458 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 2459 @*/ 2460 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 2461 { 2462 DM_Plex *mesh = (DM_Plex*) dm->data; 2463 PetscInt *closure, *fifo; 2464 const PetscInt *tmp = NULL, *tmpO = NULL; 2465 PetscInt tmpSize, t; 2466 PetscInt depth = 0, maxSize; 2467 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 2468 PetscErrorCode ierr; 2469 2470 PetscFunctionBegin; 2471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2472 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 2473 /* This is only 1-level */ 2474 if (useCone) { 2475 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 2476 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 2477 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 2478 } else { 2479 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 2480 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 2481 } 2482 if (depth == 1) { 2483 if (*points) { 2484 closure = *points; 2485 } else { 2486 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 2487 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2488 } 2489 closure[0] = p; closure[1] = ornt; 2490 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 2491 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 2492 closure[closureSize] = tmp[i]; 2493 closure[closureSize+1] = tmpO ? tmpO[i] : 0; 2494 } 2495 if (numPoints) *numPoints = closureSize/2; 2496 if (points) *points = closure; 2497 PetscFunctionReturn(0); 2498 } 2499 { 2500 PetscInt c, coneSeries, s,supportSeries; 2501 2502 c = mesh->maxConeSize; 2503 coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1; 2504 s = mesh->maxSupportSize; 2505 supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1; 2506 maxSize = 2*PetscMax(coneSeries,supportSeries); 2507 } 2508 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 2509 if (*points) { 2510 closure = *points; 2511 } else { 2512 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2513 } 2514 closure[0] = p; closure[1] = ornt; 2515 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 2516 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 2517 const PetscInt cp = tmp[i]; 2518 PetscInt co = tmpO ? tmpO[i] : 0; 2519 2520 if (ornt < 0) { 2521 PetscInt childSize, coff; 2522 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 2523 coff = co < 0 ? -(tmpO[i]+1) : tmpO[i]; 2524 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 2525 } 2526 closure[closureSize] = cp; 2527 closure[closureSize+1] = co; 2528 fifo[fifoSize] = cp; 2529 fifo[fifoSize+1] = co; 2530 } 2531 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 2532 while (fifoSize - fifoStart) { 2533 const PetscInt q = fifo[fifoStart]; 2534 const PetscInt o = fifo[fifoStart+1]; 2535 const PetscInt rev = o >= 0 ? 0 : 1; 2536 const PetscInt off = rev ? -(o+1) : o; 2537 2538 if (useCone) { 2539 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 2540 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 2541 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 2542 } else { 2543 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 2544 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 2545 tmpO = NULL; 2546 } 2547 for (t = 0; t < tmpSize; ++t) { 2548 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 2549 const PetscInt cp = tmp[i]; 2550 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 2551 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 2552 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 2553 PetscInt co = tmpO ? tmpO[i] : 0; 2554 PetscInt c; 2555 2556 if (rev) { 2557 PetscInt childSize, coff; 2558 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 2559 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 2560 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 2561 } 2562 /* Check for duplicate */ 2563 for (c = 0; c < closureSize; c += 2) { 2564 if (closure[c] == cp) break; 2565 } 2566 if (c == closureSize) { 2567 closure[closureSize] = cp; 2568 closure[closureSize+1] = co; 2569 fifo[fifoSize] = cp; 2570 fifo[fifoSize+1] = co; 2571 closureSize += 2; 2572 fifoSize += 2; 2573 } 2574 } 2575 fifoStart += 2; 2576 } 2577 if (numPoints) *numPoints = closureSize/2; 2578 if (points) *points = closure; 2579 ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 2580 PetscFunctionReturn(0); 2581 } 2582 2583 /*@C 2584 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 2585 2586 Not collective 2587 2588 Input Parameters: 2589 + mesh - The DMPlex 2590 . p - The point, which must lie in the chart set with DMPlexSetChart() 2591 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 2592 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit 2593 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit 2594 2595 Note: 2596 If not using internal storage (points is not NULL on input), this call is unnecessary 2597 2598 Fortran Notes: 2599 Since it returns an array, this routine is only available in Fortran 90, and you must 2600 include petsc.h90 in your code. 2601 2602 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2603 2604 Level: beginner 2605 2606 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 2607 @*/ 2608 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 2609 { 2610 PetscErrorCode ierr; 2611 2612 PetscFunctionBegin; 2613 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2614 if (numPoints) PetscValidIntPointer(numPoints,4); 2615 if (points) PetscValidPointer(points,5); 2616 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, points);CHKERRQ(ierr); 2617 if (numPoints) *numPoints = 0; 2618 PetscFunctionReturn(0); 2619 } 2620 2621 /*@ 2622 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 2623 2624 Not collective 2625 2626 Input Parameter: 2627 . mesh - The DMPlex 2628 2629 Output Parameters: 2630 + maxConeSize - The maximum number of in-edges 2631 - maxSupportSize - The maximum number of out-edges 2632 2633 Level: beginner 2634 2635 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 2636 @*/ 2637 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 2638 { 2639 DM_Plex *mesh = (DM_Plex*) dm->data; 2640 2641 PetscFunctionBegin; 2642 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2643 if (maxConeSize) *maxConeSize = mesh->maxConeSize; 2644 if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize; 2645 PetscFunctionReturn(0); 2646 } 2647 2648 PetscErrorCode DMSetUp_Plex(DM dm) 2649 { 2650 DM_Plex *mesh = (DM_Plex*) dm->data; 2651 PetscInt size; 2652 PetscErrorCode ierr; 2653 2654 PetscFunctionBegin; 2655 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2656 ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr); 2657 ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr); 2658 ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr); 2659 ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr); 2660 if (mesh->maxSupportSize) { 2661 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 2662 ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr); 2663 ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr); 2664 } 2665 PetscFunctionReturn(0); 2666 } 2667 2668 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 2669 { 2670 PetscErrorCode ierr; 2671 2672 PetscFunctionBegin; 2673 if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);} 2674 ierr = DMCreateSectionSubDM(dm, numFields, fields, is, subdm);CHKERRQ(ierr); 2675 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 2676 if (dm->useNatural && dm->sfMigration) { 2677 PetscSF sfMigrationInv,sfNatural; 2678 PetscSection section, sectionSeq; 2679 2680 (*subdm)->sfMigration = dm->sfMigration; 2681 ierr = PetscObjectReference((PetscObject) dm->sfMigration);CHKERRQ(ierr); 2682 ierr = DMGetLocalSection((*subdm), §ion);CHKERRQ(ierr); 2683 ierr = PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr); 2684 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq);CHKERRQ(ierr); 2685 ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr); 2686 2687 ierr = DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);CHKERRQ(ierr); 2688 (*subdm)->sfNatural = sfNatural; 2689 ierr = PetscSectionDestroy(§ionSeq);CHKERRQ(ierr); 2690 ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr); 2691 } 2692 PetscFunctionReturn(0); 2693 } 2694 2695 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 2696 { 2697 PetscErrorCode ierr; 2698 PetscInt i = 0; 2699 2700 PetscFunctionBegin; 2701 ierr = DMClone(dms[0], superdm);CHKERRQ(ierr); 2702 ierr = DMCreateSectionSuperDM(dms, len, is, superdm);CHKERRQ(ierr); 2703 (*superdm)->useNatural = PETSC_FALSE; 2704 for (i = 0; i < len; i++){ 2705 if (dms[i]->useNatural && dms[i]->sfMigration) { 2706 PetscSF sfMigrationInv,sfNatural; 2707 PetscSection section, sectionSeq; 2708 2709 (*superdm)->sfMigration = dms[i]->sfMigration; 2710 ierr = PetscObjectReference((PetscObject) dms[i]->sfMigration);CHKERRQ(ierr); 2711 (*superdm)->useNatural = PETSC_TRUE; 2712 ierr = DMGetLocalSection((*superdm), §ion);CHKERRQ(ierr); 2713 ierr = PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr); 2714 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq);CHKERRQ(ierr); 2715 ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr); 2716 2717 ierr = DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);CHKERRQ(ierr); 2718 (*superdm)->sfNatural = sfNatural; 2719 ierr = PetscSectionDestroy(§ionSeq);CHKERRQ(ierr); 2720 ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr); 2721 break; 2722 } 2723 } 2724 PetscFunctionReturn(0); 2725 } 2726 2727 /*@ 2728 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 2729 2730 Not collective 2731 2732 Input Parameter: 2733 . mesh - The DMPlex 2734 2735 Output Parameter: 2736 2737 Note: 2738 This should be called after all calls to DMPlexSetCone() 2739 2740 Level: beginner 2741 2742 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone() 2743 @*/ 2744 PetscErrorCode DMPlexSymmetrize(DM dm) 2745 { 2746 DM_Plex *mesh = (DM_Plex*) dm->data; 2747 PetscInt *offsets; 2748 PetscInt supportSize; 2749 PetscInt pStart, pEnd, p; 2750 PetscErrorCode ierr; 2751 2752 PetscFunctionBegin; 2753 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2754 if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 2755 ierr = PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr); 2756 /* Calculate support sizes */ 2757 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 2758 for (p = pStart; p < pEnd; ++p) { 2759 PetscInt dof, off, c; 2760 2761 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2762 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2763 for (c = off; c < off+dof; ++c) { 2764 ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr); 2765 } 2766 } 2767 for (p = pStart; p < pEnd; ++p) { 2768 PetscInt dof; 2769 2770 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 2771 2772 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof); 2773 } 2774 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 2775 /* Calculate supports */ 2776 ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr); 2777 ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr); 2778 ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr); 2779 for (p = pStart; p < pEnd; ++p) { 2780 PetscInt dof, off, c; 2781 2782 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2783 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2784 for (c = off; c < off+dof; ++c) { 2785 const PetscInt q = mesh->cones[c]; 2786 PetscInt offS; 2787 2788 ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr); 2789 2790 mesh->supports[offS+offsets[q]] = p; 2791 ++offsets[q]; 2792 } 2793 } 2794 ierr = PetscFree(offsets);CHKERRQ(ierr); 2795 ierr = PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr); 2796 PetscFunctionReturn(0); 2797 } 2798 2799 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 2800 { 2801 IS stratumIS; 2802 PetscErrorCode ierr; 2803 2804 PetscFunctionBegin; 2805 if (pStart >= pEnd) PetscFunctionReturn(0); 2806 #if defined(PETSC_USE_DEBUG) 2807 { 2808 PetscInt qStart, qEnd, numLevels, level; 2809 PetscBool overlap = PETSC_FALSE; 2810 ierr = DMLabelGetNumValues(label, &numLevels);CHKERRQ(ierr); 2811 for (level = 0; level < numLevels; level++) { 2812 ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr); 2813 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 2814 } 2815 if (overlap) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %D range [%D,%D) overlaps with depth %D range [%D,%D)", depth, pStart, pEnd, level, qStart, qEnd); 2816 } 2817 #endif 2818 ierr = ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);CHKERRQ(ierr); 2819 ierr = DMLabelSetStratumIS(label, depth, stratumIS);CHKERRQ(ierr); 2820 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 2821 PetscFunctionReturn(0); 2822 } 2823 2824 static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt); 2825 2826 /*@ 2827 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 2828 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 2829 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 2830 the DAG. 2831 2832 Collective on dm 2833 2834 Input Parameter: 2835 . mesh - The DMPlex 2836 2837 Output Parameter: 2838 2839 Notes: 2840 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 2841 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 2842 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 2843 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 2844 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 2845 2846 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 2847 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 2848 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 2849 to interpolate only that one (e0), so that 2850 $ cone(c0) = {e0, v2} 2851 $ cone(e0) = {v0, v1} 2852 If DMPlexStratify() is run on this mesh, it will give depths 2853 $ depth 0 = {v0, v1, v2} 2854 $ depth 1 = {e0, c0} 2855 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 2856 2857 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 2858 2859 Level: beginner 2860 2861 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes() 2862 @*/ 2863 PetscErrorCode DMPlexStratify(DM dm) 2864 { 2865 DM_Plex *mesh = (DM_Plex*) dm->data; 2866 DMLabel label; 2867 PetscInt pStart, pEnd, p; 2868 PetscInt numRoots = 0, numLeaves = 0; 2869 PetscInt cMax, fMax, eMax, vMax; 2870 PetscErrorCode ierr; 2871 2872 PetscFunctionBegin; 2873 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2874 ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 2875 2876 /* Create depth label */ 2877 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 2878 ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr); 2879 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 2880 2881 { 2882 /* Initialize roots and count leaves */ 2883 PetscInt sMin = PETSC_MAX_INT; 2884 PetscInt sMax = PETSC_MIN_INT; 2885 PetscInt coneSize, supportSize; 2886 2887 for (p = pStart; p < pEnd; ++p) { 2888 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 2889 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 2890 if (!coneSize && supportSize) { 2891 sMin = PetscMin(p, sMin); 2892 sMax = PetscMax(p, sMax); 2893 ++numRoots; 2894 } else if (!supportSize && coneSize) { 2895 ++numLeaves; 2896 } else if (!supportSize && !coneSize) { 2897 /* Isolated points */ 2898 sMin = PetscMin(p, sMin); 2899 sMax = PetscMax(p, sMax); 2900 } 2901 } 2902 ierr = DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);CHKERRQ(ierr); 2903 } 2904 2905 if (numRoots + numLeaves == (pEnd - pStart)) { 2906 PetscInt sMin = PETSC_MAX_INT; 2907 PetscInt sMax = PETSC_MIN_INT; 2908 PetscInt coneSize, supportSize; 2909 2910 for (p = pStart; p < pEnd; ++p) { 2911 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 2912 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 2913 if (!supportSize && coneSize) { 2914 sMin = PetscMin(p, sMin); 2915 sMax = PetscMax(p, sMax); 2916 } 2917 } 2918 ierr = DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);CHKERRQ(ierr); 2919 } else { 2920 PetscInt level = 0; 2921 PetscInt qStart, qEnd, q; 2922 2923 ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr); 2924 while (qEnd > qStart) { 2925 PetscInt sMin = PETSC_MAX_INT; 2926 PetscInt sMax = PETSC_MIN_INT; 2927 2928 for (q = qStart; q < qEnd; ++q) { 2929 const PetscInt *support; 2930 PetscInt supportSize, s; 2931 2932 ierr = DMPlexGetSupportSize(dm, q, &supportSize);CHKERRQ(ierr); 2933 ierr = DMPlexGetSupport(dm, q, &support);CHKERRQ(ierr); 2934 for (s = 0; s < supportSize; ++s) { 2935 sMin = PetscMin(support[s], sMin); 2936 sMax = PetscMax(support[s], sMax); 2937 } 2938 } 2939 ierr = DMLabelGetNumValues(label, &level);CHKERRQ(ierr); 2940 ierr = DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);CHKERRQ(ierr); 2941 ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr); 2942 } 2943 } 2944 { /* just in case there is an empty process */ 2945 PetscInt numValues, maxValues = 0, v; 2946 2947 ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr); 2948 ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 2949 for (v = numValues; v < maxValues; v++) { 2950 ierr = DMLabelAddStratum(label, v);CHKERRQ(ierr); 2951 } 2952 } 2953 ierr = PetscObjectStateGet((PetscObject) label, &mesh->depthState);CHKERRQ(ierr); 2954 2955 ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr); 2956 if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) { 2957 PetscInt dim; 2958 DMLabel dimLabel; 2959 2960 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2961 ierr = DMCreateLabel(dm, "dim");CHKERRQ(ierr); 2962 ierr = DMGetLabel(dm, "dim", &dimLabel);CHKERRQ(ierr); 2963 if (cMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);CHKERRQ(ierr);} 2964 if (fMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);CHKERRQ(ierr);} 2965 if (eMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);CHKERRQ(ierr);} 2966 if (vMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);CHKERRQ(ierr);} 2967 } 2968 ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 2969 PetscFunctionReturn(0); 2970 } 2971 2972 /*@ 2973 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 2974 2975 Collective on dm 2976 2977 Input Parameter: 2978 . mesh - The DMPlex 2979 2980 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 2981 2982 Level: beginner 2983 2984 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify() 2985 @*/ 2986 PetscErrorCode DMPlexComputeCellTypes(DM dm) 2987 { 2988 DM_Plex *mesh; 2989 DMLabel label; 2990 PetscInt dim, depth, gcStart, gcEnd, pStart, pEnd, p; 2991 PetscErrorCode ierr; 2992 2993 PetscFunctionBegin; 2994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2995 mesh = (DM_Plex *) dm->data; 2996 ierr = DMCreateLabel(dm, "celltype");CHKERRQ(ierr); 2997 ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr); 2998 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2999 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3000 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3001 ierr = DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);CHKERRQ(ierr); 3002 for (p = pStart; p < pEnd; ++p) { 3003 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3004 PetscInt pdepth, pheight, coneSize; 3005 3006 ierr = DMPlexGetPointDepth(dm, p, &pdepth);CHKERRQ(ierr); 3007 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 3008 pheight = depth - pdepth; 3009 if (depth <= 1) { 3010 switch (pdepth) { 3011 case 0: ct = DM_POLYTOPE_POINT;break; 3012 case 1: 3013 switch (coneSize) { 3014 case 2: ct = DM_POLYTOPE_SEGMENT;break; 3015 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 3016 case 4: 3017 switch (dim) { 3018 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 3019 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 3020 default: break; 3021 } 3022 break; 3023 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 3024 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 3025 default: break; 3026 } 3027 } 3028 } else { 3029 if (pdepth == 0) { 3030 ct = DM_POLYTOPE_POINT; 3031 } else if (pheight == 0) { 3032 if ((p >= gcStart) && (p < gcEnd)) { 3033 if (coneSize == 1) ct = DM_POLYTOPE_FV_GHOST; 3034 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ghost cell %D should have a cone size of 1, not %D", p, coneSize); 3035 } else { 3036 switch (dim) { 3037 case 1: 3038 switch (coneSize) { 3039 case 2: ct = DM_POLYTOPE_SEGMENT;break; 3040 default: break; 3041 } 3042 break; 3043 case 2: 3044 switch (coneSize) { 3045 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 3046 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 3047 default: break; 3048 } 3049 break; 3050 case 3: 3051 switch (coneSize) { 3052 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 3053 case 5: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 3054 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 3055 default: break; 3056 } 3057 break; 3058 default: break; 3059 } 3060 } 3061 } else if (pheight > 0) { 3062 switch (coneSize) { 3063 case 2: ct = DM_POLYTOPE_SEGMENT;break; 3064 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 3065 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 3066 default: break; 3067 } 3068 } 3069 } 3070 if (ct == DM_POLYTOPE_UNKNOWN) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p); 3071 ierr = DMLabelSetValue(label, p, ct);CHKERRQ(ierr); 3072 } 3073 ierr = PetscObjectStateGet((PetscObject) label, &mesh->celltypeState);CHKERRQ(ierr); 3074 ierr = PetscObjectViewFromOptions((PetscObject) label, NULL, "-dm_plex_celltypes_view");CHKERRQ(ierr); 3075 PetscFunctionReturn(0); 3076 } 3077 3078 /*@C 3079 DMPlexGetJoin - Get an array for the join of the set of points 3080 3081 Not Collective 3082 3083 Input Parameters: 3084 + dm - The DMPlex object 3085 . numPoints - The number of input points for the join 3086 - points - The input points 3087 3088 Output Parameters: 3089 + numCoveredPoints - The number of points in the join 3090 - coveredPoints - The points in the join 3091 3092 Level: intermediate 3093 3094 Note: Currently, this is restricted to a single level join 3095 3096 Fortran Notes: 3097 Since it returns an array, this routine is only available in Fortran 90, and you must 3098 include petsc.h90 in your code. 3099 3100 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3101 3102 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet() 3103 @*/ 3104 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3105 { 3106 DM_Plex *mesh = (DM_Plex*) dm->data; 3107 PetscInt *join[2]; 3108 PetscInt joinSize, i = 0; 3109 PetscInt dof, off, p, c, m; 3110 PetscErrorCode ierr; 3111 3112 PetscFunctionBegin; 3113 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3114 PetscValidIntPointer(points, 3); 3115 PetscValidIntPointer(numCoveredPoints, 4); 3116 PetscValidPointer(coveredPoints, 5); 3117 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);CHKERRQ(ierr); 3118 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);CHKERRQ(ierr); 3119 /* Copy in support of first point */ 3120 ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr); 3121 ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr); 3122 for (joinSize = 0; joinSize < dof; ++joinSize) { 3123 join[i][joinSize] = mesh->supports[off+joinSize]; 3124 } 3125 /* Check each successive support */ 3126 for (p = 1; p < numPoints; ++p) { 3127 PetscInt newJoinSize = 0; 3128 3129 ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr); 3130 ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr); 3131 for (c = 0; c < dof; ++c) { 3132 const PetscInt point = mesh->supports[off+c]; 3133 3134 for (m = 0; m < joinSize; ++m) { 3135 if (point == join[i][m]) { 3136 join[1-i][newJoinSize++] = point; 3137 break; 3138 } 3139 } 3140 } 3141 joinSize = newJoinSize; 3142 i = 1-i; 3143 } 3144 *numCoveredPoints = joinSize; 3145 *coveredPoints = join[i]; 3146 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr); 3147 PetscFunctionReturn(0); 3148 } 3149 3150 /*@C 3151 DMPlexRestoreJoin - Restore an array for the join of the set of points 3152 3153 Not Collective 3154 3155 Input Parameters: 3156 + dm - The DMPlex object 3157 . numPoints - The number of input points for the join 3158 - points - The input points 3159 3160 Output Parameters: 3161 + numCoveredPoints - The number of points in the join 3162 - coveredPoints - The points in the join 3163 3164 Fortran Notes: 3165 Since it returns an array, this routine is only available in Fortran 90, and you must 3166 include petsc.h90 in your code. 3167 3168 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3169 3170 Level: intermediate 3171 3172 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet() 3173 @*/ 3174 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3175 { 3176 PetscErrorCode ierr; 3177 3178 PetscFunctionBegin; 3179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3180 if (points) PetscValidIntPointer(points,3); 3181 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 3182 PetscValidPointer(coveredPoints, 5); 3183 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr); 3184 if (numCoveredPoints) *numCoveredPoints = 0; 3185 PetscFunctionReturn(0); 3186 } 3187 3188 /*@C 3189 DMPlexGetFullJoin - Get an array for the join of the set of points 3190 3191 Not Collective 3192 3193 Input Parameters: 3194 + dm - The DMPlex object 3195 . numPoints - The number of input points for the join 3196 - points - The input points 3197 3198 Output Parameters: 3199 + numCoveredPoints - The number of points in the join 3200 - coveredPoints - The points in the join 3201 3202 Fortran Notes: 3203 Since it returns an array, this routine is only available in Fortran 90, and you must 3204 include petsc.h90 in your code. 3205 3206 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3207 3208 Level: intermediate 3209 3210 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet() 3211 @*/ 3212 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3213 { 3214 DM_Plex *mesh = (DM_Plex*) dm->data; 3215 PetscInt *offsets, **closures; 3216 PetscInt *join[2]; 3217 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 3218 PetscInt p, d, c, m, ms; 3219 PetscErrorCode ierr; 3220 3221 PetscFunctionBegin; 3222 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3223 PetscValidIntPointer(points, 3); 3224 PetscValidIntPointer(numCoveredPoints, 4); 3225 PetscValidPointer(coveredPoints, 5); 3226 3227 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3228 ierr = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr); 3229 ierr = DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3230 ms = mesh->maxSupportSize; 3231 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 3232 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);CHKERRQ(ierr); 3233 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);CHKERRQ(ierr); 3234 3235 for (p = 0; p < numPoints; ++p) { 3236 PetscInt closureSize; 3237 3238 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr); 3239 3240 offsets[p*(depth+2)+0] = 0; 3241 for (d = 0; d < depth+1; ++d) { 3242 PetscInt pStart, pEnd, i; 3243 3244 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 3245 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 3246 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 3247 offsets[p*(depth+2)+d+1] = i; 3248 break; 3249 } 3250 } 3251 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 3252 } 3253 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); 3254 } 3255 for (d = 0; d < depth+1; ++d) { 3256 PetscInt dof; 3257 3258 /* Copy in support of first point */ 3259 dof = offsets[d+1] - offsets[d]; 3260 for (joinSize = 0; joinSize < dof; ++joinSize) { 3261 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 3262 } 3263 /* Check each successive cone */ 3264 for (p = 1; p < numPoints && joinSize; ++p) { 3265 PetscInt newJoinSize = 0; 3266 3267 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 3268 for (c = 0; c < dof; ++c) { 3269 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 3270 3271 for (m = 0; m < joinSize; ++m) { 3272 if (point == join[i][m]) { 3273 join[1-i][newJoinSize++] = point; 3274 break; 3275 } 3276 } 3277 } 3278 joinSize = newJoinSize; 3279 i = 1-i; 3280 } 3281 if (joinSize) break; 3282 } 3283 *numCoveredPoints = joinSize; 3284 *coveredPoints = join[i]; 3285 for (p = 0; p < numPoints; ++p) { 3286 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr); 3287 } 3288 ierr = PetscFree(closures);CHKERRQ(ierr); 3289 ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3290 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr); 3291 PetscFunctionReturn(0); 3292 } 3293 3294 /*@C 3295 DMPlexGetMeet - Get an array for the meet of the set of points 3296 3297 Not Collective 3298 3299 Input Parameters: 3300 + dm - The DMPlex object 3301 . numPoints - The number of input points for the meet 3302 - points - The input points 3303 3304 Output Parameters: 3305 + numCoveredPoints - The number of points in the meet 3306 - coveredPoints - The points in the meet 3307 3308 Level: intermediate 3309 3310 Note: Currently, this is restricted to a single level meet 3311 3312 Fortran Notes: 3313 Since it returns an array, this routine is only available in Fortran 90, and you must 3314 include petsc.h90 in your code. 3315 3316 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3317 3318 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin() 3319 @*/ 3320 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 3321 { 3322 DM_Plex *mesh = (DM_Plex*) dm->data; 3323 PetscInt *meet[2]; 3324 PetscInt meetSize, i = 0; 3325 PetscInt dof, off, p, c, m; 3326 PetscErrorCode ierr; 3327 3328 PetscFunctionBegin; 3329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3330 PetscValidPointer(points, 2); 3331 PetscValidPointer(numCoveringPoints, 3); 3332 PetscValidPointer(coveringPoints, 4); 3333 ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);CHKERRQ(ierr); 3334 ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);CHKERRQ(ierr); 3335 /* Copy in cone of first point */ 3336 ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr); 3337 ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr); 3338 for (meetSize = 0; meetSize < dof; ++meetSize) { 3339 meet[i][meetSize] = mesh->cones[off+meetSize]; 3340 } 3341 /* Check each successive cone */ 3342 for (p = 1; p < numPoints; ++p) { 3343 PetscInt newMeetSize = 0; 3344 3345 ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr); 3346 ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr); 3347 for (c = 0; c < dof; ++c) { 3348 const PetscInt point = mesh->cones[off+c]; 3349 3350 for (m = 0; m < meetSize; ++m) { 3351 if (point == meet[i][m]) { 3352 meet[1-i][newMeetSize++] = point; 3353 break; 3354 } 3355 } 3356 } 3357 meetSize = newMeetSize; 3358 i = 1-i; 3359 } 3360 *numCoveringPoints = meetSize; 3361 *coveringPoints = meet[i]; 3362 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr); 3363 PetscFunctionReturn(0); 3364 } 3365 3366 /*@C 3367 DMPlexRestoreMeet - Restore an array for the meet of the set of points 3368 3369 Not Collective 3370 3371 Input Parameters: 3372 + dm - The DMPlex object 3373 . numPoints - The number of input points for the meet 3374 - points - The input points 3375 3376 Output Parameters: 3377 + numCoveredPoints - The number of points in the meet 3378 - coveredPoints - The points in the meet 3379 3380 Level: intermediate 3381 3382 Fortran Notes: 3383 Since it returns an array, this routine is only available in Fortran 90, and you must 3384 include petsc.h90 in your code. 3385 3386 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3387 3388 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin() 3389 @*/ 3390 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3391 { 3392 PetscErrorCode ierr; 3393 3394 PetscFunctionBegin; 3395 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3396 if (points) PetscValidIntPointer(points,3); 3397 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 3398 PetscValidPointer(coveredPoints,5); 3399 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr); 3400 if (numCoveredPoints) *numCoveredPoints = 0; 3401 PetscFunctionReturn(0); 3402 } 3403 3404 /*@C 3405 DMPlexGetFullMeet - Get an array for the meet of the set of points 3406 3407 Not Collective 3408 3409 Input Parameters: 3410 + dm - The DMPlex object 3411 . numPoints - The number of input points for the meet 3412 - points - The input points 3413 3414 Output Parameters: 3415 + numCoveredPoints - The number of points in the meet 3416 - coveredPoints - The points in the meet 3417 3418 Level: intermediate 3419 3420 Fortran Notes: 3421 Since it returns an array, this routine is only available in Fortran 90, and you must 3422 include petsc.h90 in your code. 3423 3424 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3425 3426 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin() 3427 @*/ 3428 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3429 { 3430 DM_Plex *mesh = (DM_Plex*) dm->data; 3431 PetscInt *offsets, **closures; 3432 PetscInt *meet[2]; 3433 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 3434 PetscInt p, h, c, m, mc; 3435 PetscErrorCode ierr; 3436 3437 PetscFunctionBegin; 3438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3439 PetscValidPointer(points, 2); 3440 PetscValidPointer(numCoveredPoints, 3); 3441 PetscValidPointer(coveredPoints, 4); 3442 3443 ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr); 3444 ierr = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr); 3445 ierr = DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3446 mc = mesh->maxConeSize; 3447 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 3448 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);CHKERRQ(ierr); 3449 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);CHKERRQ(ierr); 3450 3451 for (p = 0; p < numPoints; ++p) { 3452 PetscInt closureSize; 3453 3454 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr); 3455 3456 offsets[p*(height+2)+0] = 0; 3457 for (h = 0; h < height+1; ++h) { 3458 PetscInt pStart, pEnd, i; 3459 3460 ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr); 3461 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 3462 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 3463 offsets[p*(height+2)+h+1] = i; 3464 break; 3465 } 3466 } 3467 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 3468 } 3469 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); 3470 } 3471 for (h = 0; h < height+1; ++h) { 3472 PetscInt dof; 3473 3474 /* Copy in cone of first point */ 3475 dof = offsets[h+1] - offsets[h]; 3476 for (meetSize = 0; meetSize < dof; ++meetSize) { 3477 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 3478 } 3479 /* Check each successive cone */ 3480 for (p = 1; p < numPoints && meetSize; ++p) { 3481 PetscInt newMeetSize = 0; 3482 3483 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 3484 for (c = 0; c < dof; ++c) { 3485 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 3486 3487 for (m = 0; m < meetSize; ++m) { 3488 if (point == meet[i][m]) { 3489 meet[1-i][newMeetSize++] = point; 3490 break; 3491 } 3492 } 3493 } 3494 meetSize = newMeetSize; 3495 i = 1-i; 3496 } 3497 if (meetSize) break; 3498 } 3499 *numCoveredPoints = meetSize; 3500 *coveredPoints = meet[i]; 3501 for (p = 0; p < numPoints; ++p) { 3502 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr); 3503 } 3504 ierr = PetscFree(closures);CHKERRQ(ierr); 3505 ierr = DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3506 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr); 3507 PetscFunctionReturn(0); 3508 } 3509 3510 /*@C 3511 DMPlexEqual - Determine if two DMs have the same topology 3512 3513 Not Collective 3514 3515 Input Parameters: 3516 + dmA - A DMPlex object 3517 - dmB - A DMPlex object 3518 3519 Output Parameters: 3520 . equal - PETSC_TRUE if the topologies are identical 3521 3522 Level: intermediate 3523 3524 Notes: 3525 We are not solving graph isomorphism, so we do not permutation. 3526 3527 .seealso: DMPlexGetCone() 3528 @*/ 3529 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 3530 { 3531 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 3532 PetscErrorCode ierr; 3533 3534 PetscFunctionBegin; 3535 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 3536 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 3537 PetscValidPointer(equal, 3); 3538 3539 *equal = PETSC_FALSE; 3540 ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr); 3541 ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr); 3542 if (depth != depthB) PetscFunctionReturn(0); 3543 ierr = DMPlexGetChart(dmA, &pStart, &pEnd);CHKERRQ(ierr); 3544 ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr); 3545 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 3546 for (p = pStart; p < pEnd; ++p) { 3547 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 3548 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 3549 3550 ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr); 3551 ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr); 3552 ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr); 3553 ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr); 3554 ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr); 3555 ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr); 3556 if (coneSize != coneSizeB) PetscFunctionReturn(0); 3557 for (c = 0; c < coneSize; ++c) { 3558 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 3559 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 3560 } 3561 ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr); 3562 ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr); 3563 ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr); 3564 ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr); 3565 if (supportSize != supportSizeB) PetscFunctionReturn(0); 3566 for (s = 0; s < supportSize; ++s) { 3567 if (support[s] != supportB[s]) PetscFunctionReturn(0); 3568 } 3569 } 3570 *equal = PETSC_TRUE; 3571 PetscFunctionReturn(0); 3572 } 3573 3574 /*@C 3575 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 3576 3577 Not Collective 3578 3579 Input Parameters: 3580 + dm - The DMPlex 3581 . cellDim - The cell dimension 3582 - numCorners - The number of vertices on a cell 3583 3584 Output Parameters: 3585 . numFaceVertices - The number of vertices on a face 3586 3587 Level: developer 3588 3589 Notes: 3590 Of course this can only work for a restricted set of symmetric shapes 3591 3592 .seealso: DMPlexGetCone() 3593 @*/ 3594 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 3595 { 3596 MPI_Comm comm; 3597 PetscErrorCode ierr; 3598 3599 PetscFunctionBegin; 3600 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 3601 PetscValidPointer(numFaceVertices,3); 3602 switch (cellDim) { 3603 case 0: 3604 *numFaceVertices = 0; 3605 break; 3606 case 1: 3607 *numFaceVertices = 1; 3608 break; 3609 case 2: 3610 switch (numCorners) { 3611 case 3: /* triangle */ 3612 *numFaceVertices = 2; /* Edge has 2 vertices */ 3613 break; 3614 case 4: /* quadrilateral */ 3615 *numFaceVertices = 2; /* Edge has 2 vertices */ 3616 break; 3617 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 3618 *numFaceVertices = 3; /* Edge has 3 vertices */ 3619 break; 3620 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 3621 *numFaceVertices = 3; /* Edge has 3 vertices */ 3622 break; 3623 default: 3624 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 3625 } 3626 break; 3627 case 3: 3628 switch (numCorners) { 3629 case 4: /* tetradehdron */ 3630 *numFaceVertices = 3; /* Face has 3 vertices */ 3631 break; 3632 case 6: /* tet cohesive cells */ 3633 *numFaceVertices = 4; /* Face has 4 vertices */ 3634 break; 3635 case 8: /* hexahedron */ 3636 *numFaceVertices = 4; /* Face has 4 vertices */ 3637 break; 3638 case 9: /* tet cohesive Lagrange cells */ 3639 *numFaceVertices = 6; /* Face has 6 vertices */ 3640 break; 3641 case 10: /* quadratic tetrahedron */ 3642 *numFaceVertices = 6; /* Face has 6 vertices */ 3643 break; 3644 case 12: /* hex cohesive Lagrange cells */ 3645 *numFaceVertices = 6; /* Face has 6 vertices */ 3646 break; 3647 case 18: /* quadratic tet cohesive Lagrange cells */ 3648 *numFaceVertices = 6; /* Face has 6 vertices */ 3649 break; 3650 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 3651 *numFaceVertices = 9; /* Face has 9 vertices */ 3652 break; 3653 default: 3654 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 3655 } 3656 break; 3657 default: 3658 SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim); 3659 } 3660 PetscFunctionReturn(0); 3661 } 3662 3663 /*@ 3664 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 3665 3666 Not Collective 3667 3668 Input Parameter: 3669 . dm - The DMPlex object 3670 3671 Output Parameter: 3672 . depthLabel - The DMLabel recording point depth 3673 3674 Level: developer 3675 3676 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum() 3677 @*/ 3678 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 3679 { 3680 PetscFunctionBegin; 3681 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3682 PetscValidPointer(depthLabel, 2); 3683 *depthLabel = dm->depthLabel; 3684 PetscFunctionReturn(0); 3685 } 3686 3687 /*@ 3688 DMPlexGetDepth - Get the depth of the DAG representing this mesh 3689 3690 Not Collective 3691 3692 Input Parameter: 3693 . dm - The DMPlex object 3694 3695 Output Parameter: 3696 . depth - The number of strata (breadth first levels) in the DAG 3697 3698 Level: developer 3699 3700 Notes: 3701 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 3702 The point depth is described more in detail in DMPlexSymmetrize(). 3703 3704 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), DMPlexGetPointHeight(), DMPlexSymmetrize() 3705 @*/ 3706 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 3707 { 3708 DMLabel label; 3709 PetscInt d = 0; 3710 PetscErrorCode ierr; 3711 3712 PetscFunctionBegin; 3713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3714 PetscValidPointer(depth, 2); 3715 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3716 if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);} 3717 *depth = d-1; 3718 PetscFunctionReturn(0); 3719 } 3720 3721 /*@ 3722 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 3723 3724 Not Collective 3725 3726 Input Parameters: 3727 + dm - The DMPlex object 3728 - stratumValue - The requested depth 3729 3730 Output Parameters: 3731 + start - The first point at this depth 3732 - end - One beyond the last point at this depth 3733 3734 Notes: 3735 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 3736 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 3737 higher dimension, e.g., "edges". 3738 3739 Level: developer 3740 3741 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth(), DMPlexGetPointDepth() 3742 @*/ 3743 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 3744 { 3745 DMLabel label; 3746 PetscInt pStart, pEnd; 3747 PetscErrorCode ierr; 3748 3749 PetscFunctionBegin; 3750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3751 if (start) {PetscValidPointer(start, 3); *start = 0;} 3752 if (end) {PetscValidPointer(end, 4); *end = 0;} 3753 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3754 if (pStart == pEnd) PetscFunctionReturn(0); 3755 if (stratumValue < 0) { 3756 if (start) *start = pStart; 3757 if (end) *end = pEnd; 3758 PetscFunctionReturn(0); 3759 } 3760 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3761 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 3762 ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr); 3763 PetscFunctionReturn(0); 3764 } 3765 3766 /*@ 3767 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 3768 3769 Not Collective 3770 3771 Input Parameters: 3772 + dm - The DMPlex object 3773 - stratumValue - The requested height 3774 3775 Output Parameters: 3776 + start - The first point at this height 3777 - end - One beyond the last point at this height 3778 3779 Notes: 3780 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 3781 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 3782 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 3783 3784 Level: developer 3785 3786 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth(), DMPlexGetPointHeight() 3787 @*/ 3788 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 3789 { 3790 DMLabel label; 3791 PetscInt depth, pStart, pEnd; 3792 PetscErrorCode ierr; 3793 3794 PetscFunctionBegin; 3795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3796 if (start) {PetscValidPointer(start, 3); *start = 0;} 3797 if (end) {PetscValidPointer(end, 4); *end = 0;} 3798 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3799 if (pStart == pEnd) PetscFunctionReturn(0); 3800 if (stratumValue < 0) { 3801 if (start) *start = pStart; 3802 if (end) *end = pEnd; 3803 PetscFunctionReturn(0); 3804 } 3805 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3806 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 3807 ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr); 3808 ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr); 3809 PetscFunctionReturn(0); 3810 } 3811 3812 /*@ 3813 DMPlexGetPointDepth - Get the depth of a given point 3814 3815 Not Collective 3816 3817 Input Parameter: 3818 + dm - The DMPlex object 3819 - point - The point 3820 3821 Output Parameter: 3822 . depth - The depth of the point 3823 3824 Level: intermediate 3825 3826 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointHeight() 3827 @*/ 3828 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 3829 { 3830 PetscErrorCode ierr; 3831 3832 PetscFunctionBegin; 3833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3834 PetscValidIntPointer(depth, 3); 3835 ierr = DMLabelGetValue(dm->depthLabel, point, depth);CHKERRQ(ierr); 3836 PetscFunctionReturn(0); 3837 } 3838 3839 /*@ 3840 DMPlexGetPointHeight - Get the height of a given point 3841 3842 Not Collective 3843 3844 Input Parameter: 3845 + dm - The DMPlex object 3846 - point - The point 3847 3848 Output Parameter: 3849 . height - The height of the point 3850 3851 Level: intermediate 3852 3853 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointDepth() 3854 @*/ 3855 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 3856 { 3857 PetscInt n, pDepth; 3858 PetscErrorCode ierr; 3859 3860 PetscFunctionBegin; 3861 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3862 PetscValidIntPointer(height, 3); 3863 ierr = DMLabelGetNumValues(dm->depthLabel, &n);CHKERRQ(ierr); 3864 ierr = DMLabelGetValue(dm->depthLabel, point, &pDepth);CHKERRQ(ierr); 3865 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 3866 PetscFunctionReturn(0); 3867 } 3868 3869 /*@ 3870 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 3871 3872 Not Collective 3873 3874 Input Parameter: 3875 . dm - The DMPlex object 3876 3877 Output Parameter: 3878 . celltypeLabel - The DMLabel recording cell polytope type 3879 3880 Level: developer 3881 3882 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth() 3883 @*/ 3884 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 3885 { 3886 PetscErrorCode ierr; 3887 3888 PetscFunctionBegin; 3889 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3890 PetscValidPointer(celltypeLabel, 2); 3891 if (!dm->celltypeLabel) {ierr = DMPlexComputeCellTypes(dm);CHKERRQ(ierr);} 3892 *celltypeLabel = dm->celltypeLabel; 3893 PetscFunctionReturn(0); 3894 } 3895 3896 /*@ 3897 DMPlexGetCellType - Get the polytope type of a given cell 3898 3899 Not Collective 3900 3901 Input Parameter: 3902 + dm - The DMPlex object 3903 - cell - The cell 3904 3905 Output Parameter: 3906 . celltype - The polytope type of the cell 3907 3908 Level: intermediate 3909 3910 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth() 3911 @*/ 3912 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 3913 { 3914 DMLabel label; 3915 PetscInt ct; 3916 PetscErrorCode ierr; 3917 3918 PetscFunctionBegin; 3919 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3920 PetscValidPointer(celltype, 3); 3921 ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr); 3922 ierr = DMLabelGetValue(label, cell, &ct);CHKERRQ(ierr); 3923 *celltype = (DMPolytopeType) ct; 3924 PetscFunctionReturn(0); 3925 } 3926 3927 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 3928 { 3929 PetscSection section, s; 3930 Mat m; 3931 PetscInt maxHeight; 3932 PetscErrorCode ierr; 3933 3934 PetscFunctionBegin; 3935 ierr = DMClone(dm, cdm);CHKERRQ(ierr); 3936 ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr); 3937 ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr); 3938 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 3939 ierr = DMSetLocalSection(*cdm, section);CHKERRQ(ierr); 3940 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 3941 ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr); 3942 ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr); 3943 ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr); 3944 ierr = PetscSectionDestroy(&s);CHKERRQ(ierr); 3945 ierr = MatDestroy(&m);CHKERRQ(ierr); 3946 3947 ierr = DMSetNumFields(*cdm, 1);CHKERRQ(ierr); 3948 ierr = DMCreateDS(*cdm);CHKERRQ(ierr); 3949 PetscFunctionReturn(0); 3950 } 3951 3952 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 3953 { 3954 Vec coordsLocal; 3955 DM coordsDM; 3956 PetscErrorCode ierr; 3957 3958 PetscFunctionBegin; 3959 *field = NULL; 3960 ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr); 3961 ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr); 3962 if (coordsLocal && coordsDM) { 3963 ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr); 3964 } 3965 PetscFunctionReturn(0); 3966 } 3967 3968 /*@C 3969 DMPlexGetConeSection - Return a section which describes the layout of cone data 3970 3971 Not Collective 3972 3973 Input Parameters: 3974 . dm - The DMPlex object 3975 3976 Output Parameter: 3977 . section - The PetscSection object 3978 3979 Level: developer 3980 3981 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations() 3982 @*/ 3983 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 3984 { 3985 DM_Plex *mesh = (DM_Plex*) dm->data; 3986 3987 PetscFunctionBegin; 3988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3989 if (section) *section = mesh->coneSection; 3990 PetscFunctionReturn(0); 3991 } 3992 3993 /*@C 3994 DMPlexGetSupportSection - Return a section which describes the layout of support data 3995 3996 Not Collective 3997 3998 Input Parameters: 3999 . dm - The DMPlex object 4000 4001 Output Parameter: 4002 . section - The PetscSection object 4003 4004 Level: developer 4005 4006 .seealso: DMPlexGetConeSection() 4007 @*/ 4008 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 4009 { 4010 DM_Plex *mesh = (DM_Plex*) dm->data; 4011 4012 PetscFunctionBegin; 4013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4014 if (section) *section = mesh->supportSection; 4015 PetscFunctionReturn(0); 4016 } 4017 4018 /*@C 4019 DMPlexGetCones - Return cone data 4020 4021 Not Collective 4022 4023 Input Parameters: 4024 . dm - The DMPlex object 4025 4026 Output Parameter: 4027 . cones - The cone for each point 4028 4029 Level: developer 4030 4031 .seealso: DMPlexGetConeSection() 4032 @*/ 4033 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 4034 { 4035 DM_Plex *mesh = (DM_Plex*) dm->data; 4036 4037 PetscFunctionBegin; 4038 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4039 if (cones) *cones = mesh->cones; 4040 PetscFunctionReturn(0); 4041 } 4042 4043 /*@C 4044 DMPlexGetConeOrientations - Return cone orientation data 4045 4046 Not Collective 4047 4048 Input Parameters: 4049 . dm - The DMPlex object 4050 4051 Output Parameter: 4052 . coneOrientations - The cone orientation for each point 4053 4054 Level: developer 4055 4056 .seealso: DMPlexGetConeSection() 4057 @*/ 4058 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 4059 { 4060 DM_Plex *mesh = (DM_Plex*) dm->data; 4061 4062 PetscFunctionBegin; 4063 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4064 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 4065 PetscFunctionReturn(0); 4066 } 4067 4068 /******************************** FEM Support **********************************/ 4069 4070 /* 4071 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 4072 representing a line in the section. 4073 */ 4074 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 4075 { 4076 PetscErrorCode ierr; 4077 4078 PetscFunctionBeginHot; 4079 ierr = PetscSectionGetFieldComponents(section, field, Nc);CHKERRQ(ierr); 4080 if (line < 0) { 4081 *k = 0; 4082 *Nc = 0; 4083 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 4084 *k = 1; 4085 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 4086 /* An order k SEM disc has k-1 dofs on an edge */ 4087 ierr = PetscSectionGetFieldDof(section, line, field, k);CHKERRQ(ierr); 4088 *k = *k / *Nc + 1; 4089 } 4090 PetscFunctionReturn(0); 4091 } 4092 4093 /*@ 4094 4095 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 4096 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 4097 section provided (or the section of the DM). 4098 4099 Input Parameters: 4100 + dm - The DM 4101 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 4102 - section - The PetscSection to reorder, or NULL for the default section 4103 4104 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 4105 degree of the basis. 4106 4107 Example: 4108 A typical interpolated single-quad mesh might order points as 4109 .vb 4110 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 4111 4112 v4 -- e6 -- v3 4113 | | 4114 e7 c0 e8 4115 | | 4116 v1 -- e5 -- v2 4117 .ve 4118 4119 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 4120 dofs in the order of points, e.g., 4121 .vb 4122 c0 -> [0,1,2,3] 4123 v1 -> [4] 4124 ... 4125 e5 -> [8, 9] 4126 .ve 4127 4128 which corresponds to the dofs 4129 .vb 4130 6 10 11 7 4131 13 2 3 15 4132 12 0 1 14 4133 4 8 9 5 4134 .ve 4135 4136 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 4137 .vb 4138 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 4139 .ve 4140 4141 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 4142 .vb 4143 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 4144 .ve 4145 4146 Level: developer 4147 4148 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection() 4149 @*/ 4150 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 4151 { 4152 DMLabel label; 4153 PetscInt *perm; 4154 PetscInt dim, depth = -1, eStart = -1, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 4155 PetscBool vertexchart; 4156 PetscErrorCode ierr; 4157 4158 PetscFunctionBegin; 4159 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 4160 if (dim < 1) PetscFunctionReturn(0); 4161 if (point < 0) { 4162 PetscInt sStart,sEnd; 4163 4164 ierr = DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);CHKERRQ(ierr); 4165 point = sEnd-sStart ? sStart : point; 4166 } 4167 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 4168 if (point >= 0) { ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr); } 4169 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 4170 if (depth == 1) {eStart = point;} 4171 else if (depth == dim) { 4172 const PetscInt *cone; 4173 4174 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 4175 if (dim == 2) eStart = cone[0]; 4176 else if (dim == 3) { 4177 const PetscInt *cone2; 4178 ierr = DMPlexGetCone(dm, cone[0], &cone2);CHKERRQ(ierr); 4179 eStart = cone2[0]; 4180 } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim); 4181 } else if (depth >= 0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim); 4182 { /* Determine whether the chart covers all points or just vertices. */ 4183 PetscInt pStart,pEnd,cStart,cEnd; 4184 ierr = DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);CHKERRQ(ierr); 4185 ierr = PetscSectionGetChart(section,&cStart,&cEnd);CHKERRQ(ierr); 4186 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */ 4187 else vertexchart = PETSC_FALSE; /* Assume all interpolated points are in chart */ 4188 } 4189 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 4190 for (f = 0; f < Nf; ++f) { 4191 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4192 size += PetscPowInt(k+1, dim)*Nc; 4193 } 4194 ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr); 4195 for (f = 0; f < Nf; ++f) { 4196 switch (dim) { 4197 case 1: 4198 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4199 /* 4200 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 4201 We want [ vtx0; edge of length k-1; vtx1 ] 4202 */ 4203 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 4204 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 4205 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 4206 foffset = offset; 4207 break; 4208 case 2: 4209 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 4210 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4211 /* The SEM order is 4212 4213 v_lb, {e_b}, v_rb, 4214 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 4215 v_lt, reverse {e_t}, v_rt 4216 */ 4217 { 4218 const PetscInt of = 0; 4219 const PetscInt oeb = of + PetscSqr(k-1); 4220 const PetscInt oer = oeb + (k-1); 4221 const PetscInt oet = oer + (k-1); 4222 const PetscInt oel = oet + (k-1); 4223 const PetscInt ovlb = oel + (k-1); 4224 const PetscInt ovrb = ovlb + 1; 4225 const PetscInt ovrt = ovrb + 1; 4226 const PetscInt ovlt = ovrt + 1; 4227 PetscInt o; 4228 4229 /* bottom */ 4230 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 4231 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4232 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 4233 /* middle */ 4234 for (i = 0; i < k-1; ++i) { 4235 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 4236 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; 4237 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 4238 } 4239 /* top */ 4240 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 4241 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4242 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 4243 foffset = offset; 4244 } 4245 break; 4246 case 3: 4247 /* The original hex closure is 4248 4249 {c, 4250 f_b, f_t, f_f, f_b, f_r, f_l, 4251 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 4252 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 4253 */ 4254 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4255 /* The SEM order is 4256 Bottom Slice 4257 v_blf, {e^{(k-1)-n}_bf}, v_brf, 4258 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 4259 v_blb, {e_bb}, v_brb, 4260 4261 Middle Slice (j) 4262 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 4263 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 4264 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 4265 4266 Top Slice 4267 v_tlf, {e_tf}, v_trf, 4268 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 4269 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 4270 */ 4271 { 4272 const PetscInt oc = 0; 4273 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 4274 const PetscInt oft = ofb + PetscSqr(k-1); 4275 const PetscInt off = oft + PetscSqr(k-1); 4276 const PetscInt ofk = off + PetscSqr(k-1); 4277 const PetscInt ofr = ofk + PetscSqr(k-1); 4278 const PetscInt ofl = ofr + PetscSqr(k-1); 4279 const PetscInt oebl = ofl + PetscSqr(k-1); 4280 const PetscInt oebb = oebl + (k-1); 4281 const PetscInt oebr = oebb + (k-1); 4282 const PetscInt oebf = oebr + (k-1); 4283 const PetscInt oetf = oebf + (k-1); 4284 const PetscInt oetr = oetf + (k-1); 4285 const PetscInt oetb = oetr + (k-1); 4286 const PetscInt oetl = oetb + (k-1); 4287 const PetscInt oerf = oetl + (k-1); 4288 const PetscInt oelf = oerf + (k-1); 4289 const PetscInt oelb = oelf + (k-1); 4290 const PetscInt oerb = oelb + (k-1); 4291 const PetscInt ovblf = oerb + (k-1); 4292 const PetscInt ovblb = ovblf + 1; 4293 const PetscInt ovbrb = ovblb + 1; 4294 const PetscInt ovbrf = ovbrb + 1; 4295 const PetscInt ovtlf = ovbrf + 1; 4296 const PetscInt ovtrf = ovtlf + 1; 4297 const PetscInt ovtrb = ovtrf + 1; 4298 const PetscInt ovtlb = ovtrb + 1; 4299 PetscInt o, n; 4300 4301 /* Bottom Slice */ 4302 /* bottom */ 4303 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 4304 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4305 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 4306 /* middle */ 4307 for (i = 0; i < k-1; ++i) { 4308 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 4309 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;} 4310 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 4311 } 4312 /* top */ 4313 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 4314 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4315 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 4316 4317 /* Middle Slice */ 4318 for (j = 0; j < k-1; ++j) { 4319 /* bottom */ 4320 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 4321 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; 4322 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 4323 /* middle */ 4324 for (i = 0; i < k-1; ++i) { 4325 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 4326 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; 4327 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 4328 } 4329 /* top */ 4330 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 4331 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; 4332 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 4333 } 4334 4335 /* Top Slice */ 4336 /* bottom */ 4337 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 4338 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4339 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 4340 /* middle */ 4341 for (i = 0; i < k-1; ++i) { 4342 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 4343 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 4344 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 4345 } 4346 /* top */ 4347 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 4348 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4349 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 4350 4351 foffset = offset; 4352 } 4353 break; 4354 default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim); 4355 } 4356 } 4357 if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size); 4358 /* Check permutation */ 4359 { 4360 PetscInt *check; 4361 4362 ierr = PetscMalloc1(size, &check);CHKERRQ(ierr); 4363 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]);} 4364 for (i = 0; i < size; ++i) check[perm[i]] = i; 4365 for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);} 4366 ierr = PetscFree(check);CHKERRQ(ierr); 4367 } 4368 ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr); 4369 PetscFunctionReturn(0); 4370 } 4371 4372 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 4373 { 4374 PetscDS prob; 4375 PetscInt depth, Nf, h; 4376 DMLabel label; 4377 PetscErrorCode ierr; 4378 4379 PetscFunctionBeginHot; 4380 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 4381 Nf = prob->Nf; 4382 label = dm->depthLabel; 4383 *dspace = NULL; 4384 if (field < Nf) { 4385 PetscObject disc = prob->disc[field]; 4386 4387 if (disc->classid == PETSCFE_CLASSID) { 4388 PetscDualSpace dsp; 4389 4390 ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr); 4391 ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr); 4392 ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr); 4393 h = depth - 1 - h; 4394 if (h) { 4395 ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr); 4396 } else { 4397 *dspace = dsp; 4398 } 4399 } 4400 } 4401 PetscFunctionReturn(0); 4402 } 4403 4404 4405 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4406 { 4407 PetscScalar *array, *vArray; 4408 const PetscInt *cone, *coneO; 4409 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 4410 PetscErrorCode ierr; 4411 4412 PetscFunctionBeginHot; 4413 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4414 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 4415 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 4416 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 4417 if (!values || !*values) { 4418 if ((point >= pStart) && (point < pEnd)) { 4419 PetscInt dof; 4420 4421 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4422 size += dof; 4423 } 4424 for (p = 0; p < numPoints; ++p) { 4425 const PetscInt cp = cone[p]; 4426 PetscInt dof; 4427 4428 if ((cp < pStart) || (cp >= pEnd)) continue; 4429 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4430 size += dof; 4431 } 4432 if (!values) { 4433 if (csize) *csize = size; 4434 PetscFunctionReturn(0); 4435 } 4436 ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr); 4437 } else { 4438 array = *values; 4439 } 4440 size = 0; 4441 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 4442 if ((point >= pStart) && (point < pEnd)) { 4443 PetscInt dof, off, d; 4444 PetscScalar *varr; 4445 4446 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4447 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4448 varr = &vArray[off]; 4449 for (d = 0; d < dof; ++d, ++offset) { 4450 array[offset] = varr[d]; 4451 } 4452 size += dof; 4453 } 4454 for (p = 0; p < numPoints; ++p) { 4455 const PetscInt cp = cone[p]; 4456 PetscInt o = coneO[p]; 4457 PetscInt dof, off, d; 4458 PetscScalar *varr; 4459 4460 if ((cp < pStart) || (cp >= pEnd)) continue; 4461 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4462 ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr); 4463 varr = &vArray[off]; 4464 if (o >= 0) { 4465 for (d = 0; d < dof; ++d, ++offset) { 4466 array[offset] = varr[d]; 4467 } 4468 } else { 4469 for (d = dof-1; d >= 0; --d, ++offset) { 4470 array[offset] = varr[d]; 4471 } 4472 } 4473 size += dof; 4474 } 4475 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 4476 if (!*values) { 4477 if (csize) *csize = size; 4478 *values = array; 4479 } else { 4480 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size); 4481 *csize = size; 4482 } 4483 PetscFunctionReturn(0); 4484 } 4485 4486 /* Compressed closure does not apply closure permutation */ 4487 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 4488 { 4489 const PetscInt *cla; 4490 PetscInt np, *pts = NULL; 4491 PetscErrorCode ierr; 4492 4493 PetscFunctionBeginHot; 4494 ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr); 4495 if (!*clPoints) { 4496 PetscInt pStart, pEnd, p, q; 4497 4498 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4499 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr); 4500 /* Compress out points not in the section */ 4501 for (p = 0, q = 0; p < np; p++) { 4502 PetscInt r = pts[2*p]; 4503 if ((r >= pStart) && (r < pEnd)) { 4504 pts[q*2] = r; 4505 pts[q*2+1] = pts[2*p+1]; 4506 ++q; 4507 } 4508 } 4509 np = q; 4510 cla = NULL; 4511 } else { 4512 PetscInt dof, off; 4513 4514 ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr); 4515 ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr); 4516 ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr); 4517 np = dof/2; 4518 pts = (PetscInt *) &cla[off]; 4519 } 4520 *numPoints = np; 4521 *points = pts; 4522 *clp = cla; 4523 4524 PetscFunctionReturn(0); 4525 } 4526 4527 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 4528 { 4529 PetscErrorCode ierr; 4530 4531 PetscFunctionBeginHot; 4532 if (!*clPoints) { 4533 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr); 4534 } else { 4535 ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr); 4536 } 4537 *numPoints = 0; 4538 *points = NULL; 4539 *clSec = NULL; 4540 *clPoints = NULL; 4541 *clp = NULL; 4542 PetscFunctionReturn(0); 4543 } 4544 4545 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[]) 4546 { 4547 PetscInt offset = 0, p; 4548 const PetscInt **perms = NULL; 4549 const PetscScalar **flips = NULL; 4550 PetscErrorCode ierr; 4551 4552 PetscFunctionBeginHot; 4553 *size = 0; 4554 ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 4555 for (p = 0; p < numPoints; p++) { 4556 const PetscInt point = points[2*p]; 4557 const PetscInt *perm = perms ? perms[p] : NULL; 4558 const PetscScalar *flip = flips ? flips[p] : NULL; 4559 PetscInt dof, off, d; 4560 const PetscScalar *varr; 4561 4562 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4563 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4564 varr = &vArray[off]; 4565 if (clperm) { 4566 if (perm) { 4567 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 4568 } else { 4569 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 4570 } 4571 if (flip) { 4572 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 4573 } 4574 } else { 4575 if (perm) { 4576 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 4577 } else { 4578 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 4579 } 4580 if (flip) { 4581 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 4582 } 4583 } 4584 offset += dof; 4585 } 4586 ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 4587 *size = offset; 4588 PetscFunctionReturn(0); 4589 } 4590 4591 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[]) 4592 { 4593 PetscInt offset = 0, f; 4594 PetscErrorCode ierr; 4595 4596 PetscFunctionBeginHot; 4597 *size = 0; 4598 for (f = 0; f < numFields; ++f) { 4599 PetscInt p; 4600 const PetscInt **perms = NULL; 4601 const PetscScalar **flips = NULL; 4602 4603 ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 4604 for (p = 0; p < numPoints; p++) { 4605 const PetscInt point = points[2*p]; 4606 PetscInt fdof, foff, b; 4607 const PetscScalar *varr; 4608 const PetscInt *perm = perms ? perms[p] : NULL; 4609 const PetscScalar *flip = flips ? flips[p] : NULL; 4610 4611 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4612 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4613 varr = &vArray[foff]; 4614 if (clperm) { 4615 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 4616 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 4617 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 4618 } else { 4619 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 4620 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 4621 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 4622 } 4623 offset += fdof; 4624 } 4625 ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 4626 } 4627 *size = offset; 4628 PetscFunctionReturn(0); 4629 } 4630 4631 /*@C 4632 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 4633 4634 Not collective 4635 4636 Input Parameters: 4637 + dm - The DM 4638 . section - The section describing the layout in v, or NULL to use the default section 4639 . v - The local vector 4640 . point - The point in the DM 4641 . csize - The size of the input values array, or NULL 4642 - values - An array to use for the values, or NULL to have it allocated automatically 4643 4644 Output Parameters: 4645 + csize - The number of values in the closure 4646 - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed 4647 4648 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 4649 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 4650 $ assembly function, and a user may already have allocated storage for this operation. 4651 $ 4652 $ A typical use could be 4653 $ 4654 $ values = NULL; 4655 $ ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr); 4656 $ for (cl = 0; cl < clSize; ++cl) { 4657 $ <Compute on closure> 4658 $ } 4659 $ ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr); 4660 $ 4661 $ or 4662 $ 4663 $ PetscMalloc1(clMaxSize, &values); 4664 $ for (p = pStart; p < pEnd; ++p) { 4665 $ clSize = clMaxSize; 4666 $ ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr); 4667 $ for (cl = 0; cl < clSize; ++cl) { 4668 $ <Compute on closure> 4669 $ } 4670 $ } 4671 $ PetscFree(values); 4672 4673 Fortran Notes: 4674 Since it returns an array, this routine is only available in Fortran 90, and you must 4675 include petsc.h90 in your code. 4676 4677 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 4678 4679 Level: intermediate 4680 4681 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 4682 @*/ 4683 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4684 { 4685 PetscSection clSection; 4686 IS clPoints; 4687 PetscScalar *array; 4688 const PetscScalar *vArray; 4689 PetscInt *points = NULL; 4690 const PetscInt *clp, *perm; 4691 PetscInt depth, numFields, numPoints, size; 4692 PetscErrorCode ierr; 4693 4694 PetscFunctionBeginHot; 4695 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4696 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 4697 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4698 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 4699 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 4700 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4701 if (depth == 1 && numFields < 2) { 4702 ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr); 4703 PetscFunctionReturn(0); 4704 } 4705 /* Get points */ 4706 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4707 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr); 4708 /* Get array */ 4709 if (!values || !*values) { 4710 PetscInt asize = 0, dof, p; 4711 4712 for (p = 0; p < numPoints*2; p += 2) { 4713 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4714 asize += dof; 4715 } 4716 if (!values) { 4717 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4718 if (csize) *csize = asize; 4719 PetscFunctionReturn(0); 4720 } 4721 ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr); 4722 } else { 4723 array = *values; 4724 } 4725 ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr); 4726 /* Get values */ 4727 if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);} 4728 else {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);CHKERRQ(ierr);} 4729 /* Cleanup points */ 4730 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4731 /* Cleanup array */ 4732 ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr); 4733 if (!*values) { 4734 if (csize) *csize = size; 4735 *values = array; 4736 } else { 4737 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size); 4738 *csize = size; 4739 } 4740 PetscFunctionReturn(0); 4741 } 4742 4743 /*@C 4744 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 4745 4746 Not collective 4747 4748 Input Parameters: 4749 + dm - The DM 4750 . section - The section describing the layout in v, or NULL to use the default section 4751 . v - The local vector 4752 . point - The point in the DM 4753 . csize - The number of values in the closure, or NULL 4754 - values - The array of values, which is a borrowed array and should not be freed 4755 4756 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 4757 4758 Fortran Notes: 4759 Since it returns an array, this routine is only available in Fortran 90, and you must 4760 include petsc.h90 in your code. 4761 4762 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 4763 4764 Level: intermediate 4765 4766 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 4767 @*/ 4768 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4769 { 4770 PetscInt size = 0; 4771 PetscErrorCode ierr; 4772 4773 PetscFunctionBegin; 4774 /* Should work without recalculating size */ 4775 ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr); 4776 *values = NULL; 4777 PetscFunctionReturn(0); 4778 } 4779 4780 PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;} 4781 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;} 4782 4783 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[]) 4784 { 4785 PetscInt cdof; /* The number of constraints on this point */ 4786 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 4787 PetscScalar *a; 4788 PetscInt off, cind = 0, k; 4789 PetscErrorCode ierr; 4790 4791 PetscFunctionBegin; 4792 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 4793 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4794 a = &array[off]; 4795 if (!cdof || setBC) { 4796 if (clperm) { 4797 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 4798 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 4799 } else { 4800 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 4801 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 4802 } 4803 } else { 4804 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 4805 if (clperm) { 4806 if (perm) {for (k = 0; k < dof; ++k) { 4807 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4808 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 4809 } 4810 } else { 4811 for (k = 0; k < dof; ++k) { 4812 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4813 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 4814 } 4815 } 4816 } else { 4817 if (perm) { 4818 for (k = 0; k < dof; ++k) { 4819 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4820 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 4821 } 4822 } else { 4823 for (k = 0; k < dof; ++k) { 4824 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4825 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 4826 } 4827 } 4828 } 4829 } 4830 PetscFunctionReturn(0); 4831 } 4832 4833 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[]) 4834 { 4835 PetscInt cdof; /* The number of constraints on this point */ 4836 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 4837 PetscScalar *a; 4838 PetscInt off, cind = 0, k; 4839 PetscErrorCode ierr; 4840 4841 PetscFunctionBegin; 4842 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 4843 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4844 a = &array[off]; 4845 if (cdof) { 4846 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 4847 if (clperm) { 4848 if (perm) { 4849 for (k = 0; k < dof; ++k) { 4850 if ((cind < cdof) && (k == cdofs[cind])) { 4851 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 4852 cind++; 4853 } 4854 } 4855 } else { 4856 for (k = 0; k < dof; ++k) { 4857 if ((cind < cdof) && (k == cdofs[cind])) { 4858 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 4859 cind++; 4860 } 4861 } 4862 } 4863 } else { 4864 if (perm) { 4865 for (k = 0; k < dof; ++k) { 4866 if ((cind < cdof) && (k == cdofs[cind])) { 4867 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 4868 cind++; 4869 } 4870 } 4871 } else { 4872 for (k = 0; k < dof; ++k) { 4873 if ((cind < cdof) && (k == cdofs[cind])) { 4874 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 4875 cind++; 4876 } 4877 } 4878 } 4879 } 4880 } 4881 PetscFunctionReturn(0); 4882 } 4883 4884 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[]) 4885 { 4886 PetscScalar *a; 4887 PetscInt fdof, foff, fcdof, foffset = *offset; 4888 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 4889 PetscInt cind = 0, b; 4890 PetscErrorCode ierr; 4891 4892 PetscFunctionBegin; 4893 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4894 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 4895 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4896 a = &array[foff]; 4897 if (!fcdof || setBC) { 4898 if (clperm) { 4899 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 4900 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 4901 } else { 4902 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 4903 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 4904 } 4905 } else { 4906 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 4907 if (clperm) { 4908 if (perm) { 4909 for (b = 0; b < fdof; b++) { 4910 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 4911 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 4912 } 4913 } else { 4914 for (b = 0; b < fdof; b++) { 4915 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 4916 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 4917 } 4918 } 4919 } else { 4920 if (perm) { 4921 for (b = 0; b < fdof; b++) { 4922 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 4923 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 4924 } 4925 } else { 4926 for (b = 0; b < fdof; b++) { 4927 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 4928 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 4929 } 4930 } 4931 } 4932 } 4933 *offset += fdof; 4934 PetscFunctionReturn(0); 4935 } 4936 4937 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[]) 4938 { 4939 PetscScalar *a; 4940 PetscInt fdof, foff, fcdof, foffset = *offset; 4941 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 4942 PetscInt cind = 0, ncind = 0, b; 4943 PetscBool ncSet, fcSet; 4944 PetscErrorCode ierr; 4945 4946 PetscFunctionBegin; 4947 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4948 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 4949 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4950 a = &array[foff]; 4951 if (fcdof) { 4952 /* We just override fcdof and fcdofs with Ncc and comps */ 4953 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 4954 if (clperm) { 4955 if (perm) { 4956 if (comps) { 4957 for (b = 0; b < fdof; b++) { 4958 ncSet = fcSet = PETSC_FALSE; 4959 if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;} 4960 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 4961 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 4962 } 4963 } else { 4964 for (b = 0; b < fdof; b++) { 4965 if ((cind < fcdof) && (b == fcdofs[cind])) { 4966 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 4967 ++cind; 4968 } 4969 } 4970 } 4971 } else { 4972 if (comps) { 4973 for (b = 0; b < fdof; b++) { 4974 ncSet = fcSet = PETSC_FALSE; 4975 if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;} 4976 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 4977 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 4978 } 4979 } else { 4980 for (b = 0; b < fdof; b++) { 4981 if ((cind < fcdof) && (b == fcdofs[cind])) { 4982 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 4983 ++cind; 4984 } 4985 } 4986 } 4987 } 4988 } else { 4989 if (perm) { 4990 if (comps) { 4991 for (b = 0; b < fdof; b++) { 4992 ncSet = fcSet = PETSC_FALSE; 4993 if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;} 4994 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 4995 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 4996 } 4997 } else { 4998 for (b = 0; b < fdof; b++) { 4999 if ((cind < fcdof) && (b == fcdofs[cind])) { 5000 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 5001 ++cind; 5002 } 5003 } 5004 } 5005 } else { 5006 if (comps) { 5007 for (b = 0; b < fdof; b++) { 5008 ncSet = fcSet = PETSC_FALSE; 5009 if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;} 5010 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 5011 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 5012 } 5013 } else { 5014 for (b = 0; b < fdof; b++) { 5015 if ((cind < fcdof) && (b == fcdofs[cind])) { 5016 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 5017 ++cind; 5018 } 5019 } 5020 } 5021 } 5022 } 5023 } 5024 *offset += fdof; 5025 PetscFunctionReturn(0); 5026 } 5027 5028 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 5029 { 5030 PetscScalar *array; 5031 const PetscInt *cone, *coneO; 5032 PetscInt pStart, pEnd, p, numPoints, off, dof; 5033 PetscErrorCode ierr; 5034 5035 PetscFunctionBeginHot; 5036 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 5037 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 5038 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 5039 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 5040 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5041 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 5042 const PetscInt cp = !p ? point : cone[p-1]; 5043 const PetscInt o = !p ? 0 : coneO[p-1]; 5044 5045 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 5046 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 5047 /* ADD_VALUES */ 5048 { 5049 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5050 PetscScalar *a; 5051 PetscInt cdof, coff, cind = 0, k; 5052 5053 ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr); 5054 ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr); 5055 a = &array[coff]; 5056 if (!cdof) { 5057 if (o >= 0) { 5058 for (k = 0; k < dof; ++k) { 5059 a[k] += values[off+k]; 5060 } 5061 } else { 5062 for (k = 0; k < dof; ++k) { 5063 a[k] += values[off+dof-k-1]; 5064 } 5065 } 5066 } else { 5067 ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr); 5068 if (o >= 0) { 5069 for (k = 0; k < dof; ++k) { 5070 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5071 a[k] += values[off+k]; 5072 } 5073 } else { 5074 for (k = 0; k < dof; ++k) { 5075 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5076 a[k] += values[off+dof-k-1]; 5077 } 5078 } 5079 } 5080 } 5081 } 5082 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5083 PetscFunctionReturn(0); 5084 } 5085 5086 /*@C 5087 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 5088 5089 Not collective 5090 5091 Input Parameters: 5092 + dm - The DM 5093 . section - The section describing the layout in v, or NULL to use the default section 5094 . v - The local vector 5095 . point - The point in the DM 5096 . values - The array of values 5097 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 5098 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 5099 5100 Fortran Notes: 5101 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 5102 5103 Level: intermediate 5104 5105 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure() 5106 @*/ 5107 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 5108 { 5109 PetscSection clSection; 5110 IS clPoints; 5111 PetscScalar *array; 5112 PetscInt *points = NULL; 5113 const PetscInt *clp, *clperm; 5114 PetscInt depth, numFields, numPoints, p; 5115 PetscErrorCode ierr; 5116 5117 PetscFunctionBeginHot; 5118 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5119 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 5120 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5121 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5122 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5123 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5124 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 5125 ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr); 5126 PetscFunctionReturn(0); 5127 } 5128 /* Get points */ 5129 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr); 5130 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5131 /* Get array */ 5132 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5133 /* Get values */ 5134 if (numFields > 0) { 5135 PetscInt offset = 0, f; 5136 for (f = 0; f < numFields; ++f) { 5137 const PetscInt **perms = NULL; 5138 const PetscScalar **flips = NULL; 5139 5140 ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5141 switch (mode) { 5142 case INSERT_VALUES: 5143 for (p = 0; p < numPoints; p++) { 5144 const PetscInt point = points[2*p]; 5145 const PetscInt *perm = perms ? perms[p] : NULL; 5146 const PetscScalar *flip = flips ? flips[p] : NULL; 5147 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 5148 } break; 5149 case INSERT_ALL_VALUES: 5150 for (p = 0; p < numPoints; p++) { 5151 const PetscInt point = points[2*p]; 5152 const PetscInt *perm = perms ? perms[p] : NULL; 5153 const PetscScalar *flip = flips ? flips[p] : NULL; 5154 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 5155 } break; 5156 case INSERT_BC_VALUES: 5157 for (p = 0; p < numPoints; p++) { 5158 const PetscInt point = points[2*p]; 5159 const PetscInt *perm = perms ? perms[p] : NULL; 5160 const PetscScalar *flip = flips ? flips[p] : NULL; 5161 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 5162 } break; 5163 case ADD_VALUES: 5164 for (p = 0; p < numPoints; p++) { 5165 const PetscInt point = points[2*p]; 5166 const PetscInt *perm = perms ? perms[p] : NULL; 5167 const PetscScalar *flip = flips ? flips[p] : NULL; 5168 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 5169 } break; 5170 case ADD_ALL_VALUES: 5171 for (p = 0; p < numPoints; p++) { 5172 const PetscInt point = points[2*p]; 5173 const PetscInt *perm = perms ? perms[p] : NULL; 5174 const PetscScalar *flip = flips ? flips[p] : NULL; 5175 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 5176 } break; 5177 case ADD_BC_VALUES: 5178 for (p = 0; p < numPoints; p++) { 5179 const PetscInt point = points[2*p]; 5180 const PetscInt *perm = perms ? perms[p] : NULL; 5181 const PetscScalar *flip = flips ? flips[p] : NULL; 5182 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 5183 } break; 5184 default: 5185 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 5186 } 5187 ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5188 } 5189 } else { 5190 PetscInt dof, off; 5191 const PetscInt **perms = NULL; 5192 const PetscScalar **flips = NULL; 5193 5194 ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5195 switch (mode) { 5196 case INSERT_VALUES: 5197 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5198 const PetscInt point = points[2*p]; 5199 const PetscInt *perm = perms ? perms[p] : NULL; 5200 const PetscScalar *flip = flips ? flips[p] : NULL; 5201 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5202 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 5203 } break; 5204 case INSERT_ALL_VALUES: 5205 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5206 const PetscInt point = points[2*p]; 5207 const PetscInt *perm = perms ? perms[p] : NULL; 5208 const PetscScalar *flip = flips ? flips[p] : NULL; 5209 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5210 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 5211 } break; 5212 case INSERT_BC_VALUES: 5213 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5214 const PetscInt point = points[2*p]; 5215 const PetscInt *perm = perms ? perms[p] : NULL; 5216 const PetscScalar *flip = flips ? flips[p] : NULL; 5217 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5218 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 5219 } break; 5220 case ADD_VALUES: 5221 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5222 const PetscInt point = points[2*p]; 5223 const PetscInt *perm = perms ? perms[p] : NULL; 5224 const PetscScalar *flip = flips ? flips[p] : NULL; 5225 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5226 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 5227 } break; 5228 case ADD_ALL_VALUES: 5229 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5230 const PetscInt point = points[2*p]; 5231 const PetscInt *perm = perms ? perms[p] : NULL; 5232 const PetscScalar *flip = flips ? flips[p] : NULL; 5233 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5234 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 5235 } break; 5236 case ADD_BC_VALUES: 5237 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5238 const PetscInt point = points[2*p]; 5239 const PetscInt *perm = perms ? perms[p] : NULL; 5240 const PetscScalar *flip = flips ? flips[p] : NULL; 5241 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5242 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 5243 } break; 5244 default: 5245 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 5246 } 5247 ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5248 } 5249 /* Cleanup points */ 5250 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5251 /* Cleanup array */ 5252 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5253 PetscFunctionReturn(0); 5254 } 5255 5256 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 5257 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode) 5258 { 5259 PetscSection clSection; 5260 IS clPoints; 5261 PetscScalar *array; 5262 PetscInt *points = NULL; 5263 const PetscInt *clp; 5264 PetscInt numFields, numPoints, p; 5265 PetscInt offset = 0, f; 5266 PetscErrorCode ierr; 5267 5268 PetscFunctionBeginHot; 5269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5270 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 5271 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5272 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5273 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5274 /* Get points */ 5275 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5276 /* Get array */ 5277 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5278 /* Get values */ 5279 for (f = 0; f < numFields; ++f) { 5280 const PetscInt **perms = NULL; 5281 const PetscScalar **flips = NULL; 5282 5283 if (!fieldActive[f]) { 5284 for (p = 0; p < numPoints*2; p += 2) { 5285 PetscInt fdof; 5286 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 5287 offset += fdof; 5288 } 5289 continue; 5290 } 5291 ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5292 switch (mode) { 5293 case INSERT_VALUES: 5294 for (p = 0; p < numPoints; p++) { 5295 const PetscInt point = points[2*p]; 5296 const PetscInt *perm = perms ? perms[p] : NULL; 5297 const PetscScalar *flip = flips ? flips[p] : NULL; 5298 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array); 5299 } break; 5300 case INSERT_ALL_VALUES: 5301 for (p = 0; p < numPoints; p++) { 5302 const PetscInt point = points[2*p]; 5303 const PetscInt *perm = perms ? perms[p] : NULL; 5304 const PetscScalar *flip = flips ? flips[p] : NULL; 5305 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array); 5306 } break; 5307 case INSERT_BC_VALUES: 5308 for (p = 0; p < numPoints; p++) { 5309 const PetscInt point = points[2*p]; 5310 const PetscInt *perm = perms ? perms[p] : NULL; 5311 const PetscScalar *flip = flips ? flips[p] : NULL; 5312 updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array); 5313 } break; 5314 case ADD_VALUES: 5315 for (p = 0; p < numPoints; p++) { 5316 const PetscInt point = points[2*p]; 5317 const PetscInt *perm = perms ? perms[p] : NULL; 5318 const PetscScalar *flip = flips ? flips[p] : NULL; 5319 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array); 5320 } break; 5321 case ADD_ALL_VALUES: 5322 for (p = 0; p < numPoints; p++) { 5323 const PetscInt point = points[2*p]; 5324 const PetscInt *perm = perms ? perms[p] : NULL; 5325 const PetscScalar *flip = flips ? flips[p] : NULL; 5326 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array); 5327 } break; 5328 default: 5329 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 5330 } 5331 ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5332 } 5333 /* Cleanup points */ 5334 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5335 /* Cleanup array */ 5336 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5337 PetscFunctionReturn(0); 5338 } 5339 5340 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 5341 { 5342 PetscMPIInt rank; 5343 PetscInt i, j; 5344 PetscErrorCode ierr; 5345 5346 PetscFunctionBegin; 5347 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr); 5348 ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr); 5349 for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);} 5350 for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);} 5351 numCIndices = numCIndices ? numCIndices : numRIndices; 5352 for (i = 0; i < numRIndices; i++) { 5353 ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr); 5354 for (j = 0; j < numCIndices; j++) { 5355 #if defined(PETSC_USE_COMPLEX) 5356 ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr); 5357 #else 5358 ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr); 5359 #endif 5360 } 5361 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 5362 } 5363 PetscFunctionReturn(0); 5364 } 5365 5366 /* 5367 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 5368 5369 Input Parameters: 5370 + section - The section for this data layout 5371 . islocal - Is the section (and thus indices being requested) local or global? 5372 . point - The point contributing dofs with these indices 5373 . off - The global offset of this point 5374 . loff - The local offset of each field 5375 . setBC - The flag determining whether to include indices of bounsary values 5376 . perm - A permutation of the dofs on this point, or NULL 5377 - indperm - A permutation of the entire indices array, or NULL 5378 5379 Output Parameter: 5380 . indices - Indices for dofs on this point 5381 5382 Level: developer 5383 5384 Note: The indices could be local or global, depending on the value of 'off'. 5385 */ 5386 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 5387 { 5388 PetscInt dof; /* The number of unknowns on this point */ 5389 PetscInt cdof; /* The number of constraints on this point */ 5390 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5391 PetscInt cind = 0, k; 5392 PetscErrorCode ierr; 5393 5394 PetscFunctionBegin; 5395 if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 5396 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5397 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 5398 if (!cdof || setBC) { 5399 for (k = 0; k < dof; ++k) { 5400 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 5401 const PetscInt ind = indperm ? indperm[preind] : preind; 5402 5403 indices[ind] = off + k; 5404 } 5405 } else { 5406 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 5407 for (k = 0; k < dof; ++k) { 5408 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 5409 const PetscInt ind = indperm ? indperm[preind] : preind; 5410 5411 if ((cind < cdof) && (k == cdofs[cind])) { 5412 /* Insert check for returning constrained indices */ 5413 indices[ind] = -(off+k+1); 5414 ++cind; 5415 } else { 5416 indices[ind] = off + k - (islocal ? 0 : cind); 5417 } 5418 } 5419 } 5420 *loff += dof; 5421 PetscFunctionReturn(0); 5422 } 5423 5424 /* 5425 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 5426 5427 Input Parameters: 5428 + section - a section (global or local) 5429 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 5430 . point - point within section 5431 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 5432 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 5433 . setBC - identify constrained (boundary condition) points via involution. 5434 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 5435 . permsoff - offset 5436 - indperm - index permutation 5437 5438 Output Parameter: 5439 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 5440 . indices - array to hold indices (as defined by section) of each dof associated with point 5441 5442 Notes: 5443 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 5444 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 5445 in the local vector. 5446 5447 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 5448 significant). It is invalid to call with a global section and setBC=true. 5449 5450 Developer Note: 5451 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 5452 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 5453 offset could be obtained from the section instead of passing it explicitly as we do now. 5454 5455 Example: 5456 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 5457 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 5458 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 5459 The global vector does not store constrained dofs, so when this function returns global indices, say {110, -112, 111}, the value of -112 is an arbitrary flag that should not be interpreted beyond its sign. 5460 5461 Level: developer 5462 */ 5463 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 5464 { 5465 PetscInt numFields, foff, f; 5466 PetscErrorCode ierr; 5467 5468 PetscFunctionBegin; 5469 if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 5470 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5471 for (f = 0, foff = 0; f < numFields; ++f) { 5472 PetscInt fdof, cfdof; 5473 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5474 PetscInt cind = 0, b; 5475 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 5476 5477 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5478 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr); 5479 if (!cfdof || setBC) { 5480 for (b = 0; b < fdof; ++b) { 5481 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 5482 const PetscInt ind = indperm ? indperm[preind] : preind; 5483 5484 indices[ind] = off+foff+b; 5485 } 5486 } else { 5487 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5488 for (b = 0; b < fdof; ++b) { 5489 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 5490 const PetscInt ind = indperm ? indperm[preind] : preind; 5491 5492 if ((cind < cfdof) && (b == fcdofs[cind])) { 5493 indices[ind] = -(off+foff+b+1); 5494 ++cind; 5495 } else { 5496 indices[ind] = off + foff + b - (islocal ? 0 : cind); 5497 } 5498 } 5499 } 5500 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 5501 foffs[f] += fdof; 5502 } 5503 PetscFunctionReturn(0); 5504 } 5505 5506 /* 5507 This version believes the globalSection offsets for each field, rather than just the point offset 5508 5509 . foffs - The offset into 'indices' for each field, since it is segregated by field 5510 5511 Notes: 5512 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 5513 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 5514 */ 5515 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 5516 { 5517 PetscInt numFields, foff, f; 5518 PetscErrorCode ierr; 5519 5520 PetscFunctionBegin; 5521 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5522 for (f = 0; f < numFields; ++f) { 5523 PetscInt fdof, cfdof; 5524 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5525 PetscInt cind = 0, b; 5526 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 5527 5528 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5529 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr); 5530 ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr); 5531 if (!cfdof) { 5532 for (b = 0; b < fdof; ++b) { 5533 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 5534 const PetscInt ind = indperm ? indperm[preind] : preind; 5535 5536 indices[ind] = foff+b; 5537 } 5538 } else { 5539 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5540 for (b = 0; b < fdof; ++b) { 5541 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 5542 const PetscInt ind = indperm ? indperm[preind] : preind; 5543 5544 if ((cind < cfdof) && (b == fcdofs[cind])) { 5545 indices[ind] = -(foff+b+1); 5546 ++cind; 5547 } else { 5548 indices[ind] = foff+b-cind; 5549 } 5550 } 5551 } 5552 foffs[f] += fdof; 5553 } 5554 PetscFunctionReturn(0); 5555 } 5556 5557 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) 5558 { 5559 Mat cMat; 5560 PetscSection aSec, cSec; 5561 IS aIS; 5562 PetscInt aStart = -1, aEnd = -1; 5563 const PetscInt *anchors; 5564 PetscInt numFields, f, p, q, newP = 0; 5565 PetscInt newNumPoints = 0, newNumIndices = 0; 5566 PetscInt *newPoints, *indices, *newIndices; 5567 PetscInt maxAnchor, maxDof; 5568 PetscInt newOffsets[32]; 5569 PetscInt *pointMatOffsets[32]; 5570 PetscInt *newPointOffsets[32]; 5571 PetscScalar *pointMat[32]; 5572 PetscScalar *newValues=NULL,*tmpValues; 5573 PetscBool anyConstrained = PETSC_FALSE; 5574 PetscErrorCode ierr; 5575 5576 PetscFunctionBegin; 5577 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5578 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5579 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5580 5581 ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr); 5582 /* if there are point-to-point constraints */ 5583 if (aSec) { 5584 ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr); 5585 ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); 5586 ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr); 5587 /* figure out how many points are going to be in the new element matrix 5588 * (we allow double counting, because it's all just going to be summed 5589 * into the global matrix anyway) */ 5590 for (p = 0; p < 2*numPoints; p+=2) { 5591 PetscInt b = points[p]; 5592 PetscInt bDof = 0, bSecDof; 5593 5594 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 5595 if (!bSecDof) { 5596 continue; 5597 } 5598 if (b >= aStart && b < aEnd) { 5599 ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr); 5600 } 5601 if (bDof) { 5602 /* this point is constrained */ 5603 /* it is going to be replaced by its anchors */ 5604 PetscInt bOff, q; 5605 5606 anyConstrained = PETSC_TRUE; 5607 newNumPoints += bDof; 5608 ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr); 5609 for (q = 0; q < bDof; q++) { 5610 PetscInt a = anchors[bOff + q]; 5611 PetscInt aDof; 5612 5613 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 5614 newNumIndices += aDof; 5615 for (f = 0; f < numFields; ++f) { 5616 PetscInt fDof; 5617 5618 ierr = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr); 5619 newOffsets[f+1] += fDof; 5620 } 5621 } 5622 } 5623 else { 5624 /* this point is not constrained */ 5625 newNumPoints++; 5626 newNumIndices += bSecDof; 5627 for (f = 0; f < numFields; ++f) { 5628 PetscInt fDof; 5629 5630 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 5631 newOffsets[f+1] += fDof; 5632 } 5633 } 5634 } 5635 } 5636 if (!anyConstrained) { 5637 if (outNumPoints) *outNumPoints = 0; 5638 if (outNumIndices) *outNumIndices = 0; 5639 if (outPoints) *outPoints = NULL; 5640 if (outValues) *outValues = NULL; 5641 if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);} 5642 PetscFunctionReturn(0); 5643 } 5644 5645 if (outNumPoints) *outNumPoints = newNumPoints; 5646 if (outNumIndices) *outNumIndices = newNumIndices; 5647 5648 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 5649 5650 if (!outPoints && !outValues) { 5651 if (offsets) { 5652 for (f = 0; f <= numFields; f++) { 5653 offsets[f] = newOffsets[f]; 5654 } 5655 } 5656 if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);} 5657 PetscFunctionReturn(0); 5658 } 5659 5660 if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices); 5661 5662 ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr); 5663 5664 /* workspaces */ 5665 if (numFields) { 5666 for (f = 0; f < numFields; f++) { 5667 ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr); 5668 ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr); 5669 } 5670 } 5671 else { 5672 ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr); 5673 ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr); 5674 } 5675 5676 /* get workspaces for the point-to-point matrices */ 5677 if (numFields) { 5678 PetscInt totalOffset, totalMatOffset; 5679 5680 for (p = 0; p < numPoints; p++) { 5681 PetscInt b = points[2*p]; 5682 PetscInt bDof = 0, bSecDof; 5683 5684 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 5685 if (!bSecDof) { 5686 for (f = 0; f < numFields; f++) { 5687 newPointOffsets[f][p + 1] = 0; 5688 pointMatOffsets[f][p + 1] = 0; 5689 } 5690 continue; 5691 } 5692 if (b >= aStart && b < aEnd) { 5693 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 5694 } 5695 if (bDof) { 5696 for (f = 0; f < numFields; f++) { 5697 PetscInt fDof, q, bOff, allFDof = 0; 5698 5699 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 5700 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 5701 for (q = 0; q < bDof; q++) { 5702 PetscInt a = anchors[bOff + q]; 5703 PetscInt aFDof; 5704 5705 ierr = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr); 5706 allFDof += aFDof; 5707 } 5708 newPointOffsets[f][p+1] = allFDof; 5709 pointMatOffsets[f][p+1] = fDof * allFDof; 5710 } 5711 } 5712 else { 5713 for (f = 0; f < numFields; f++) { 5714 PetscInt fDof; 5715 5716 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 5717 newPointOffsets[f][p+1] = fDof; 5718 pointMatOffsets[f][p+1] = 0; 5719 } 5720 } 5721 } 5722 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 5723 newPointOffsets[f][0] = totalOffset; 5724 pointMatOffsets[f][0] = totalMatOffset; 5725 for (p = 0; p < numPoints; p++) { 5726 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 5727 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 5728 } 5729 totalOffset = newPointOffsets[f][numPoints]; 5730 totalMatOffset = pointMatOffsets[f][numPoints]; 5731 ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr); 5732 } 5733 } 5734 else { 5735 for (p = 0; p < numPoints; p++) { 5736 PetscInt b = points[2*p]; 5737 PetscInt bDof = 0, bSecDof; 5738 5739 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 5740 if (!bSecDof) { 5741 newPointOffsets[0][p + 1] = 0; 5742 pointMatOffsets[0][p + 1] = 0; 5743 continue; 5744 } 5745 if (b >= aStart && b < aEnd) { 5746 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 5747 } 5748 if (bDof) { 5749 PetscInt bOff, q, allDof = 0; 5750 5751 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 5752 for (q = 0; q < bDof; q++) { 5753 PetscInt a = anchors[bOff + q], aDof; 5754 5755 ierr = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr); 5756 allDof += aDof; 5757 } 5758 newPointOffsets[0][p+1] = allDof; 5759 pointMatOffsets[0][p+1] = bSecDof * allDof; 5760 } 5761 else { 5762 newPointOffsets[0][p+1] = bSecDof; 5763 pointMatOffsets[0][p+1] = 0; 5764 } 5765 } 5766 newPointOffsets[0][0] = 0; 5767 pointMatOffsets[0][0] = 0; 5768 for (p = 0; p < numPoints; p++) { 5769 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 5770 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 5771 } 5772 ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr); 5773 } 5774 5775 /* output arrays */ 5776 ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr); 5777 5778 /* get the point-to-point matrices; construct newPoints */ 5779 ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr); 5780 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 5781 ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr); 5782 ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr); 5783 if (numFields) { 5784 for (p = 0, newP = 0; p < numPoints; p++) { 5785 PetscInt b = points[2*p]; 5786 PetscInt o = points[2*p+1]; 5787 PetscInt bDof = 0, bSecDof; 5788 5789 ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr); 5790 if (!bSecDof) { 5791 continue; 5792 } 5793 if (b >= aStart && b < aEnd) { 5794 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 5795 } 5796 if (bDof) { 5797 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 5798 5799 fStart[0] = 0; 5800 fEnd[0] = 0; 5801 for (f = 0; f < numFields; f++) { 5802 PetscInt fDof; 5803 5804 ierr = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr); 5805 fStart[f+1] = fStart[f] + fDof; 5806 fEnd[f+1] = fStart[f+1]; 5807 } 5808 ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr); 5809 ierr = DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr); 5810 5811 fAnchorStart[0] = 0; 5812 fAnchorEnd[0] = 0; 5813 for (f = 0; f < numFields; f++) { 5814 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 5815 5816 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 5817 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 5818 } 5819 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 5820 for (q = 0; q < bDof; q++) { 5821 PetscInt a = anchors[bOff + q], aOff; 5822 5823 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 5824 newPoints[2*(newP + q)] = a; 5825 newPoints[2*(newP + q) + 1] = 0; 5826 ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr); 5827 ierr = DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr); 5828 } 5829 newP += bDof; 5830 5831 if (outValues) { 5832 /* get the point-to-point submatrix */ 5833 for (f = 0; f < numFields; f++) { 5834 ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr); 5835 } 5836 } 5837 } 5838 else { 5839 newPoints[2 * newP] = b; 5840 newPoints[2 * newP + 1] = o; 5841 newP++; 5842 } 5843 } 5844 } else { 5845 for (p = 0; p < numPoints; p++) { 5846 PetscInt b = points[2*p]; 5847 PetscInt o = points[2*p+1]; 5848 PetscInt bDof = 0, bSecDof; 5849 5850 ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr); 5851 if (!bSecDof) { 5852 continue; 5853 } 5854 if (b >= aStart && b < aEnd) { 5855 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 5856 } 5857 if (bDof) { 5858 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 5859 5860 ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr); 5861 ierr = DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr); 5862 5863 ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr); 5864 for (q = 0; q < bDof; q++) { 5865 PetscInt a = anchors[bOff + q], aOff; 5866 5867 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 5868 5869 newPoints[2*(newP + q)] = a; 5870 newPoints[2*(newP + q) + 1] = 0; 5871 ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr); 5872 ierr = DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr); 5873 } 5874 newP += bDof; 5875 5876 /* get the point-to-point submatrix */ 5877 if (outValues) { 5878 ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr); 5879 } 5880 } 5881 else { 5882 newPoints[2 * newP] = b; 5883 newPoints[2 * newP + 1] = o; 5884 newP++; 5885 } 5886 } 5887 } 5888 5889 if (outValues) { 5890 ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr); 5891 ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr); 5892 /* multiply constraints on the right */ 5893 if (numFields) { 5894 for (f = 0; f < numFields; f++) { 5895 PetscInt oldOff = offsets[f]; 5896 5897 for (p = 0; p < numPoints; p++) { 5898 PetscInt cStart = newPointOffsets[f][p]; 5899 PetscInt b = points[2 * p]; 5900 PetscInt c, r, k; 5901 PetscInt dof; 5902 5903 ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr); 5904 if (!dof) { 5905 continue; 5906 } 5907 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 5908 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 5909 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 5910 5911 for (r = 0; r < numIndices; r++) { 5912 for (c = 0; c < nCols; c++) { 5913 for (k = 0; k < dof; k++) { 5914 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 5915 } 5916 } 5917 } 5918 } 5919 else { 5920 /* copy this column as is */ 5921 for (r = 0; r < numIndices; r++) { 5922 for (c = 0; c < dof; c++) { 5923 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 5924 } 5925 } 5926 } 5927 oldOff += dof; 5928 } 5929 } 5930 } 5931 else { 5932 PetscInt oldOff = 0; 5933 for (p = 0; p < numPoints; p++) { 5934 PetscInt cStart = newPointOffsets[0][p]; 5935 PetscInt b = points[2 * p]; 5936 PetscInt c, r, k; 5937 PetscInt dof; 5938 5939 ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr); 5940 if (!dof) { 5941 continue; 5942 } 5943 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 5944 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 5945 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 5946 5947 for (r = 0; r < numIndices; r++) { 5948 for (c = 0; c < nCols; c++) { 5949 for (k = 0; k < dof; k++) { 5950 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 5951 } 5952 } 5953 } 5954 } 5955 else { 5956 /* copy this column as is */ 5957 for (r = 0; r < numIndices; r++) { 5958 for (c = 0; c < dof; c++) { 5959 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 5960 } 5961 } 5962 } 5963 oldOff += dof; 5964 } 5965 } 5966 5967 if (multiplyLeft) { 5968 ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr); 5969 ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr); 5970 /* multiply constraints transpose on the left */ 5971 if (numFields) { 5972 for (f = 0; f < numFields; f++) { 5973 PetscInt oldOff = offsets[f]; 5974 5975 for (p = 0; p < numPoints; p++) { 5976 PetscInt rStart = newPointOffsets[f][p]; 5977 PetscInt b = points[2 * p]; 5978 PetscInt c, r, k; 5979 PetscInt dof; 5980 5981 ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr); 5982 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 5983 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 5984 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 5985 5986 for (r = 0; r < nRows; r++) { 5987 for (c = 0; c < newNumIndices; c++) { 5988 for (k = 0; k < dof; k++) { 5989 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 5990 } 5991 } 5992 } 5993 } 5994 else { 5995 /* copy this row as is */ 5996 for (r = 0; r < dof; r++) { 5997 for (c = 0; c < newNumIndices; c++) { 5998 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 5999 } 6000 } 6001 } 6002 oldOff += dof; 6003 } 6004 } 6005 } 6006 else { 6007 PetscInt oldOff = 0; 6008 6009 for (p = 0; p < numPoints; p++) { 6010 PetscInt rStart = newPointOffsets[0][p]; 6011 PetscInt b = points[2 * p]; 6012 PetscInt c, r, k; 6013 PetscInt dof; 6014 6015 ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr); 6016 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 6017 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 6018 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 6019 6020 for (r = 0; r < nRows; r++) { 6021 for (c = 0; c < newNumIndices; c++) { 6022 for (k = 0; k < dof; k++) { 6023 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 6024 } 6025 } 6026 } 6027 } 6028 else { 6029 /* copy this row as is */ 6030 for (r = 0; r < dof; r++) { 6031 for (c = 0; c < newNumIndices; c++) { 6032 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 6033 } 6034 } 6035 } 6036 oldOff += dof; 6037 } 6038 } 6039 6040 ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr); 6041 } 6042 else { 6043 newValues = tmpValues; 6044 } 6045 } 6046 6047 /* clean up */ 6048 ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr); 6049 ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr); 6050 6051 if (numFields) { 6052 for (f = 0; f < numFields; f++) { 6053 ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr); 6054 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr); 6055 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr); 6056 } 6057 } 6058 else { 6059 ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr); 6060 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr); 6061 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr); 6062 } 6063 ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); 6064 6065 /* output */ 6066 if (outPoints) { 6067 *outPoints = newPoints; 6068 } 6069 else { 6070 ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr); 6071 } 6072 if (outValues) { 6073 *outValues = newValues; 6074 } 6075 for (f = 0; f <= numFields; f++) { 6076 offsets[f] = newOffsets[f]; 6077 } 6078 PetscFunctionReturn(0); 6079 } 6080 6081 /*@C 6082 DMPlexGetClosureIndices - Get the global indices for all local points in the closure of the given point 6083 6084 Not collective 6085 6086 Input Parameters: 6087 + dm - The DM 6088 . section - The section describing the points (a local section) 6089 . idxSection - The section on which to obtain indices (may be local or global) 6090 - point - The mesh point 6091 6092 Output parameters: 6093 + numIndices - The number of indices 6094 . indices - The indices 6095 - outOffsets - Field offset if not NULL 6096 6097 Notes: 6098 Must call DMPlexRestoreClosureIndices() to free allocated memory 6099 6100 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 6101 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 6102 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 6103 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 6104 indices (with the above semantics) are implied. 6105 6106 Level: advanced 6107 6108 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection() 6109 @*/ 6110 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets) 6111 { 6112 PetscBool isLocal = (PetscBool)(section == idxSection); 6113 PetscSection clSection; 6114 IS clPoints; 6115 const PetscInt *clp, *clperm; 6116 const PetscInt **perms[32] = {NULL}; 6117 PetscInt *points = NULL, *pointsNew; 6118 PetscInt numPoints, numPointsNew; 6119 PetscInt offsets[32]; 6120 PetscInt Nf, Nind, NindNew, off, idxOff, f, p; 6121 PetscErrorCode ierr; 6122 6123 PetscFunctionBegin; 6124 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6125 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6126 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 6127 if (numIndices) PetscValidPointer(numIndices, 4); 6128 PetscValidPointer(indices, 5); 6129 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 6130 if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf); 6131 ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr); 6132 /* Get points in closure */ 6133 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6134 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr); 6135 /* Get number of indices and indices per field */ 6136 for (p = 0, Nind = 0; p < numPoints*2; p += 2) { 6137 PetscInt dof, fdof; 6138 6139 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 6140 for (f = 0; f < Nf; ++f) { 6141 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 6142 offsets[f+1] += fdof; 6143 } 6144 Nind += dof; 6145 } 6146 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 6147 if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind); 6148 if (!Nf) offsets[1] = Nind; 6149 /* Get dual space symmetries */ 6150 for (f = 0; f < PetscMax(1,Nf); f++) { 6151 if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6152 else {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6153 } 6154 /* Correct for hanging node constraints */ 6155 { 6156 ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr); 6157 if (numPointsNew) { 6158 for (f = 0; f < PetscMax(1,Nf); f++) { 6159 if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6160 else {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6161 } 6162 for (f = 0; f < PetscMax(1,Nf); f++) { 6163 if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);} 6164 else {ierr = PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);} 6165 } 6166 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6167 numPoints = numPointsNew; 6168 Nind = NindNew; 6169 points = pointsNew; 6170 } 6171 } 6172 /* Calculate indices */ 6173 ierr = DMGetWorkArray(dm, Nind, MPIU_INT, indices);CHKERRQ(ierr); 6174 if (Nf) { 6175 if (outOffsets) { 6176 PetscInt f; 6177 6178 for (f = 0; f <= Nf; f++) { 6179 outOffsets[f] = offsets[f]; 6180 } 6181 } 6182 for (p = 0; p < numPoints; p++) { 6183 ierr = PetscSectionGetOffset(idxSection, points[2*p], &idxOff);CHKERRQ(ierr); 6184 ierr = DMPlexGetIndicesPointFields_Internal(section, isLocal, points[2*p], idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);CHKERRQ(ierr); 6185 } 6186 } else { 6187 for (p = 0, off = 0; p < numPoints; p++) { 6188 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 6189 6190 ierr = PetscSectionGetOffset(idxSection, points[2*p], &idxOff);CHKERRQ(ierr); 6191 ierr = DMPlexGetIndicesPoint_Internal(section, isLocal, points[2*p], idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, *indices);CHKERRQ(ierr); 6192 } 6193 } 6194 /* Cleanup points */ 6195 for (f = 0; f < PetscMax(1,Nf); f++) { 6196 if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6197 else {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6198 } 6199 if (numPointsNew) { 6200 ierr = DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);CHKERRQ(ierr); 6201 } else { 6202 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6203 } 6204 if (numIndices) *numIndices = Nind; 6205 PetscFunctionReturn(0); 6206 } 6207 6208 /*@C 6209 DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point 6210 6211 Not collective 6212 6213 Input Parameters: 6214 + dm - The DM 6215 . section - The section describing the layout in v, or NULL to use the default section 6216 . globalSection - The section describing the parallel layout in v, or NULL to use the default section 6217 . point - The mesh point 6218 . numIndices - The number of indices 6219 . indices - The indices 6220 - outOffsets - Field offset if not NULL 6221 6222 Level: advanced 6223 6224 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure() 6225 @*/ 6226 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets) 6227 { 6228 PetscErrorCode ierr; 6229 6230 PetscFunctionBegin; 6231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6232 PetscValidPointer(indices, 5); 6233 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr); 6234 PetscFunctionReturn(0); 6235 } 6236 6237 /*@C 6238 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 6239 6240 Not collective 6241 6242 Input Parameters: 6243 + dm - The DM 6244 . section - The section describing the layout in v, or NULL to use the default section 6245 . globalSection - The section describing the layout in v, or NULL to use the default global section 6246 . A - The matrix 6247 . point - The point in the DM 6248 . values - The array of values 6249 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 6250 6251 Fortran Notes: 6252 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6253 6254 Level: intermediate 6255 6256 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure() 6257 @*/ 6258 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 6259 { 6260 DM_Plex *mesh = (DM_Plex*) dm->data; 6261 PetscSection clSection; 6262 IS clPoints; 6263 PetscInt *points = NULL, *newPoints; 6264 const PetscInt *clp, *clperm; 6265 PetscInt *indices; 6266 PetscInt offsets[32]; 6267 const PetscInt **perms[32] = {NULL}; 6268 const PetscScalar **flips[32] = {NULL}; 6269 PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f; 6270 PetscScalar *valCopy = NULL; 6271 PetscScalar *newValues; 6272 PetscErrorCode ierr; 6273 6274 PetscFunctionBegin; 6275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6276 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 6277 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6278 if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);} 6279 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 6280 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 6281 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 6282 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 6283 ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr); 6284 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr); 6285 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6286 for (p = 0, numIndices = 0; p < numPoints*2; p += 2) { 6287 PetscInt fdof; 6288 6289 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 6290 for (f = 0; f < numFields; ++f) { 6291 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 6292 offsets[f+1] += fdof; 6293 } 6294 numIndices += dof; 6295 } 6296 for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f]; 6297 6298 if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices); 6299 /* Get symmetries */ 6300 for (f = 0; f < PetscMax(1,numFields); f++) { 6301 if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6302 else {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6303 if (values && flips[f]) { /* may need to apply sign changes to the element matrix */ 6304 PetscInt foffset = offsets[f]; 6305 6306 for (p = 0; p < numPoints; p++) { 6307 PetscInt point = points[2*p], fdof; 6308 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 6309 6310 if (!numFields) { 6311 ierr = PetscSectionGetDof(section,point,&fdof);CHKERRQ(ierr); 6312 } else { 6313 ierr = PetscSectionGetFieldDof(section,point,f,&fdof);CHKERRQ(ierr); 6314 } 6315 if (flip) { 6316 PetscInt i, j, k; 6317 6318 if (!valCopy) { 6319 ierr = DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr); 6320 for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j]; 6321 values = valCopy; 6322 } 6323 for (i = 0; i < fdof; i++) { 6324 PetscScalar fval = flip[i]; 6325 6326 for (k = 0; k < numIndices; k++) { 6327 valCopy[numIndices * (foffset + i) + k] *= fval; 6328 valCopy[numIndices * k + (foffset + i)] *= fval; 6329 } 6330 } 6331 } 6332 foffset += fdof; 6333 } 6334 } 6335 } 6336 ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr); 6337 if (newNumPoints) { 6338 if (valCopy) { 6339 ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr); 6340 } 6341 for (f = 0; f < PetscMax(1,numFields); f++) { 6342 if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6343 else {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6344 } 6345 for (f = 0; f < PetscMax(1,numFields); f++) { 6346 if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);} 6347 else {ierr = PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);} 6348 } 6349 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6350 numPoints = newNumPoints; 6351 numIndices = newNumIndices; 6352 points = newPoints; 6353 values = newValues; 6354 } 6355 ierr = DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr); 6356 if (numFields) { 6357 PetscBool useFieldOffsets; 6358 6359 ierr = PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);CHKERRQ(ierr); 6360 if (useFieldOffsets) { 6361 for (p = 0; p < numPoints; p++) { 6362 ierr = DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, perms, p, clperm, indices);CHKERRQ(ierr); 6363 } 6364 } else { 6365 for (p = 0; p < numPoints; p++) { 6366 ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr); 6367 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 6368 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 6369 * global section. */ 6370 ierr = DMPlexGetIndicesPointFields_Internal(section, PETSC_FALSE, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);CHKERRQ(ierr); 6371 } 6372 } 6373 } else { 6374 for (p = 0, off = 0; p < numPoints; p++) { 6375 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 6376 ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr); 6377 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 6378 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 6379 * global section. */ 6380 ierr = DMPlexGetIndicesPoint_Internal(section, PETSC_FALSE, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);CHKERRQ(ierr); 6381 } 6382 } 6383 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);} 6384 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);CHKERRQ(ierr); 6385 if (mesh->printFEM > 1) { 6386 PetscInt i; 6387 ierr = PetscPrintf(PETSC_COMM_SELF, " Indices:");CHKERRQ(ierr); 6388 for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);} 6389 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 6390 } 6391 if (ierr) { 6392 PetscMPIInt rank; 6393 PetscErrorCode ierr2; 6394 6395 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2); 6396 ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 6397 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2); 6398 ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2); 6399 CHKERRQ(ierr); 6400 } 6401 for (f = 0; f < PetscMax(1,numFields); f++) { 6402 if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6403 else {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6404 } 6405 if (newNumPoints) { 6406 ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr); 6407 ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr); 6408 } 6409 else { 6410 if (valCopy) { 6411 ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr); 6412 } 6413 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6414 } 6415 ierr = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr); 6416 PetscFunctionReturn(0); 6417 } 6418 6419 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 6420 { 6421 DM_Plex *mesh = (DM_Plex*) dmf->data; 6422 PetscInt *fpoints = NULL, *ftotpoints = NULL; 6423 PetscInt *cpoints = NULL; 6424 PetscInt *findices, *cindices; 6425 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 6426 PetscInt foffsets[32], coffsets[32]; 6427 CellRefiner cellRefiner; 6428 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 6429 PetscErrorCode ierr; 6430 6431 PetscFunctionBegin; 6432 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 6433 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 6434 if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);} 6435 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 6436 if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);} 6437 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 6438 if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);} 6439 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 6440 if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);} 6441 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 6442 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 6443 ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr); 6444 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 6445 ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr); 6446 ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr); 6447 /* Column indices */ 6448 ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 6449 maxFPoints = numCPoints; 6450 /* Compress out points not in the section */ 6451 /* TODO: Squeeze out points with 0 dof as well */ 6452 ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr); 6453 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 6454 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 6455 cpoints[q*2] = cpoints[p]; 6456 cpoints[q*2+1] = cpoints[p+1]; 6457 ++q; 6458 } 6459 } 6460 numCPoints = q; 6461 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 6462 PetscInt fdof; 6463 6464 ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr); 6465 if (!dof) continue; 6466 for (f = 0; f < numFields; ++f) { 6467 ierr = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr); 6468 coffsets[f+1] += fdof; 6469 } 6470 numCIndices += dof; 6471 } 6472 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 6473 /* Row indices */ 6474 ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr); 6475 ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr); 6476 ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 6477 for (r = 0, q = 0; r < numSubcells; ++r) { 6478 /* TODO Map from coarse to fine cells */ 6479 ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 6480 /* Compress out points not in the section */ 6481 ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr); 6482 for (p = 0; p < numFPoints*2; p += 2) { 6483 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 6484 ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr); 6485 if (!dof) continue; 6486 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 6487 if (s < q) continue; 6488 ftotpoints[q*2] = fpoints[p]; 6489 ftotpoints[q*2+1] = fpoints[p+1]; 6490 ++q; 6491 } 6492 } 6493 ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 6494 } 6495 numFPoints = q; 6496 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 6497 PetscInt fdof; 6498 6499 ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr); 6500 if (!dof) continue; 6501 for (f = 0; f < numFields; ++f) { 6502 ierr = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr); 6503 foffsets[f+1] += fdof; 6504 } 6505 numFIndices += dof; 6506 } 6507 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 6508 6509 if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 6510 if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 6511 ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr); 6512 ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr); 6513 if (numFields) { 6514 const PetscInt **permsF[32] = {NULL}; 6515 const PetscInt **permsC[32] = {NULL}; 6516 6517 for (f = 0; f < numFields; f++) { 6518 ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 6519 ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 6520 } 6521 for (p = 0; p < numFPoints; p++) { 6522 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 6523 ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr); 6524 } 6525 for (p = 0; p < numCPoints; p++) { 6526 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 6527 ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr); 6528 } 6529 for (f = 0; f < numFields; f++) { 6530 ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 6531 ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 6532 } 6533 } else { 6534 const PetscInt **permsF = NULL; 6535 const PetscInt **permsC = NULL; 6536 6537 ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 6538 ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 6539 for (p = 0, off = 0; p < numFPoints; p++) { 6540 const PetscInt *perm = permsF ? permsF[p] : NULL; 6541 6542 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 6543 ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr); 6544 } 6545 for (p = 0, off = 0; p < numCPoints; p++) { 6546 const PetscInt *perm = permsC ? permsC[p] : NULL; 6547 6548 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 6549 ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr); 6550 } 6551 ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 6552 ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 6553 } 6554 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);} 6555 /* TODO: flips */ 6556 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 6557 if (ierr) { 6558 PetscMPIInt rank; 6559 PetscErrorCode ierr2; 6560 6561 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2); 6562 ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 6563 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2); 6564 ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2); 6565 ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2); 6566 CHKERRQ(ierr); 6567 } 6568 ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 6569 ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 6570 ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr); 6571 ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr); 6572 PetscFunctionReturn(0); 6573 } 6574 6575 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 6576 { 6577 PetscInt *fpoints = NULL, *ftotpoints = NULL; 6578 PetscInt *cpoints = NULL; 6579 PetscInt foffsets[32], coffsets[32]; 6580 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 6581 CellRefiner cellRefiner; 6582 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 6583 PetscErrorCode ierr; 6584 6585 PetscFunctionBegin; 6586 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 6587 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 6588 if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);} 6589 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 6590 if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);} 6591 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 6592 if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);} 6593 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 6594 if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);} 6595 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 6596 ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr); 6597 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 6598 ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr); 6599 ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr); 6600 /* Column indices */ 6601 ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 6602 maxFPoints = numCPoints; 6603 /* Compress out points not in the section */ 6604 /* TODO: Squeeze out points with 0 dof as well */ 6605 ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr); 6606 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 6607 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 6608 cpoints[q*2] = cpoints[p]; 6609 cpoints[q*2+1] = cpoints[p+1]; 6610 ++q; 6611 } 6612 } 6613 numCPoints = q; 6614 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 6615 PetscInt fdof; 6616 6617 ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr); 6618 if (!dof) continue; 6619 for (f = 0; f < numFields; ++f) { 6620 ierr = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr); 6621 coffsets[f+1] += fdof; 6622 } 6623 numCIndices += dof; 6624 } 6625 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 6626 /* Row indices */ 6627 ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr); 6628 ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr); 6629 ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 6630 for (r = 0, q = 0; r < numSubcells; ++r) { 6631 /* TODO Map from coarse to fine cells */ 6632 ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 6633 /* Compress out points not in the section */ 6634 ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr); 6635 for (p = 0; p < numFPoints*2; p += 2) { 6636 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 6637 ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr); 6638 if (!dof) continue; 6639 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 6640 if (s < q) continue; 6641 ftotpoints[q*2] = fpoints[p]; 6642 ftotpoints[q*2+1] = fpoints[p+1]; 6643 ++q; 6644 } 6645 } 6646 ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 6647 } 6648 numFPoints = q; 6649 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 6650 PetscInt fdof; 6651 6652 ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr); 6653 if (!dof) continue; 6654 for (f = 0; f < numFields; ++f) { 6655 ierr = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr); 6656 foffsets[f+1] += fdof; 6657 } 6658 numFIndices += dof; 6659 } 6660 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 6661 6662 if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 6663 if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 6664 if (numFields) { 6665 const PetscInt **permsF[32] = {NULL}; 6666 const PetscInt **permsC[32] = {NULL}; 6667 6668 for (f = 0; f < numFields; f++) { 6669 ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 6670 ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 6671 } 6672 for (p = 0; p < numFPoints; p++) { 6673 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 6674 ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr); 6675 } 6676 for (p = 0; p < numCPoints; p++) { 6677 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 6678 ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr); 6679 } 6680 for (f = 0; f < numFields; f++) { 6681 ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 6682 ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 6683 } 6684 } else { 6685 const PetscInt **permsF = NULL; 6686 const PetscInt **permsC = NULL; 6687 6688 ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 6689 ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 6690 for (p = 0, off = 0; p < numFPoints; p++) { 6691 const PetscInt *perm = permsF ? permsF[p] : NULL; 6692 6693 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 6694 ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr); 6695 } 6696 for (p = 0, off = 0; p < numCPoints; p++) { 6697 const PetscInt *perm = permsC ? permsC[p] : NULL; 6698 6699 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 6700 ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr); 6701 } 6702 ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 6703 ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 6704 } 6705 ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 6706 ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 6707 PetscFunctionReturn(0); 6708 } 6709 6710 /*@ 6711 DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid 6712 6713 Input Parameter: 6714 . dm - The DMPlex object 6715 6716 Output Parameters: 6717 + cMax - The first hybrid cell 6718 . fMax - The first hybrid face 6719 . eMax - The first hybrid edge 6720 - vMax - The first hybrid vertex 6721 6722 Level: developer 6723 6724 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds() 6725 @*/ 6726 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax) 6727 { 6728 DM_Plex *mesh = (DM_Plex*) dm->data; 6729 PetscInt dim; 6730 PetscErrorCode ierr; 6731 6732 PetscFunctionBegin; 6733 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6734 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 6735 if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set"); 6736 if (cMax) *cMax = mesh->hybridPointMax[dim]; 6737 if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)]; 6738 if (eMax) *eMax = mesh->hybridPointMax[1]; 6739 if (vMax) *vMax = mesh->hybridPointMax[0]; 6740 PetscFunctionReturn(0); 6741 } 6742 6743 static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax) 6744 { 6745 IS is, his; 6746 PetscInt first = 0, stride; 6747 PetscBool isStride; 6748 PetscErrorCode ierr; 6749 6750 PetscFunctionBegin; 6751 ierr = DMLabelGetStratumIS(depthLabel, d, &is);CHKERRQ(ierr); 6752 ierr = PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);CHKERRQ(ierr); 6753 if (isStride) {ierr = ISStrideGetInfo(is, &first, &stride);CHKERRQ(ierr);} 6754 if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d); 6755 ierr = ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);CHKERRQ(ierr); 6756 ierr = DMLabelSetStratumIS(dimLabel, d, his);CHKERRQ(ierr); 6757 ierr = ISDestroy(&his);CHKERRQ(ierr); 6758 ierr = ISDestroy(&is);CHKERRQ(ierr); 6759 PetscFunctionReturn(0); 6760 } 6761 6762 /*@ 6763 DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid 6764 6765 Input Parameters: 6766 + dm - The DMPlex object 6767 . cMax - The first hybrid cell 6768 . fMax - The first hybrid face 6769 . eMax - The first hybrid edge 6770 - vMax - The first hybrid vertex 6771 6772 Level: developer 6773 6774 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds() 6775 @*/ 6776 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax) 6777 { 6778 DM_Plex *mesh = (DM_Plex*) dm->data; 6779 PetscInt dim; 6780 PetscErrorCode ierr; 6781 6782 PetscFunctionBegin; 6783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6784 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 6785 if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set"); 6786 if (cMax >= 0) mesh->hybridPointMax[dim] = cMax; 6787 if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax; 6788 if (eMax >= 0) mesh->hybridPointMax[1] = eMax; 6789 if (vMax >= 0) mesh->hybridPointMax[0] = vMax; 6790 PetscFunctionReturn(0); 6791 } 6792 6793 /*@C 6794 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 6795 6796 Input Parameter: 6797 . dm - The DMPlex object 6798 6799 Output Parameter: 6800 . cellHeight - The height of a cell 6801 6802 Level: developer 6803 6804 .seealso DMPlexSetVTKCellHeight() 6805 @*/ 6806 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 6807 { 6808 DM_Plex *mesh = (DM_Plex*) dm->data; 6809 6810 PetscFunctionBegin; 6811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6812 PetscValidPointer(cellHeight, 2); 6813 *cellHeight = mesh->vtkCellHeight; 6814 PetscFunctionReturn(0); 6815 } 6816 6817 /*@C 6818 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 6819 6820 Input Parameters: 6821 + dm - The DMPlex object 6822 - cellHeight - The height of a cell 6823 6824 Level: developer 6825 6826 .seealso DMPlexGetVTKCellHeight() 6827 @*/ 6828 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 6829 { 6830 DM_Plex *mesh = (DM_Plex*) dm->data; 6831 6832 PetscFunctionBegin; 6833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6834 mesh->vtkCellHeight = cellHeight; 6835 PetscFunctionReturn(0); 6836 } 6837 6838 /*@ 6839 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 6840 6841 Input Parameter: 6842 . dm - The DMPlex object 6843 6844 Output Parameters: 6845 + gcStart - The first ghost cell, or NULL 6846 - gcEnd - The upper bound on ghost cells, or NULL 6847 6848 Level: advanced 6849 6850 .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds() 6851 @*/ 6852 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 6853 { 6854 DM_Plex *mesh = (DM_Plex*) dm->data; 6855 PetscInt dim; 6856 PetscErrorCode ierr; 6857 6858 PetscFunctionBegin; 6859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6860 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 6861 if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set"); 6862 if (gcStart) {PetscValidIntPointer(gcStart, 2); *gcStart = mesh->ghostCellStart;} 6863 if (gcEnd) { 6864 PetscValidIntPointer(gcEnd, 3); 6865 if (mesh->ghostCellStart >= 0) {ierr = DMPlexGetHeightStratum(dm, 0, NULL, gcEnd);CHKERRQ(ierr);} 6866 else {*gcEnd = -1;} 6867 } 6868 PetscFunctionReturn(0); 6869 } 6870 6871 /*@ 6872 DMPlexSetGhostCellStratum - Set the range of cells which are used to enforce FV boundary conditions 6873 6874 Input Parameters: 6875 + dm - The DMPlex object 6876 . gcStart - The first ghost cell, or PETSC_DETERMINE 6877 - gcEnd - The upper bound on ghost cells, or PETSC_DETERMINE 6878 6879 Level: advanced 6880 6881 Note: This is not usually called directly by a user. 6882 6883 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum(), DMPlexSetHybridBounds() 6884 @*/ 6885 PetscErrorCode DMPlexSetGhostCellStratum(DM dm, PetscInt gcStart, PetscInt gcEnd) 6886 { 6887 DM_Plex *mesh = (DM_Plex*) dm->data; 6888 PetscInt dim; 6889 PetscErrorCode ierr; 6890 6891 PetscFunctionBegin; 6892 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6893 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 6894 if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set"); 6895 mesh->ghostCellStart = gcStart; 6896 if (gcEnd >= 0) { 6897 PetscInt cEnd; 6898 ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr); 6899 if (gcEnd != cEnd) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Ghost cells must appear at the end of the cell range, but gcEnd %D is not equal to cEnd %D", gcEnd, cEnd); 6900 } 6901 PetscFunctionReturn(0); 6902 } 6903 6904 /*@ 6905 DMPlexGetInteriorCellStratum - Get the range of cells which are neither hybrid nor ghost FV cells 6906 6907 Input Parameter: 6908 . dm - The DMPlex object 6909 6910 Output Parameters: 6911 + cStartInterior - The first ghost cell 6912 - cEndInterior - The upper bound on ghost cells 6913 6914 Level: developer 6915 6916 .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds() 6917 @*/ 6918 PetscErrorCode DMPlexGetInteriorCellStratum(DM dm, PetscInt *cStartInterior, PetscInt *cEndInterior) 6919 { 6920 PetscInt gcEnd, cMax; 6921 PetscErrorCode ierr; 6922 6923 PetscFunctionBegin; 6924 ierr = DMPlexGetHeightStratum(dm, 0, cStartInterior, cEndInterior);CHKERRQ(ierr); 6925 ierr = DMPlexGetGhostCellStratum(dm, &gcEnd, NULL);CHKERRQ(ierr); 6926 *cEndInterior = gcEnd < 0 ? *cEndInterior : gcEnd; 6927 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 6928 *cEndInterior = cMax < 0 ? *cEndInterior : cMax; 6929 PetscFunctionReturn(0); 6930 } 6931 6932 /* We can easily have a form that takes an IS instead */ 6933 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 6934 { 6935 PetscSection section, globalSection; 6936 PetscInt *numbers, p; 6937 PetscErrorCode ierr; 6938 6939 PetscFunctionBegin; 6940 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 6941 ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr); 6942 for (p = pStart; p < pEnd; ++p) { 6943 ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr); 6944 } 6945 ierr = PetscSectionSetUp(section);CHKERRQ(ierr); 6946 ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr); 6947 ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr); 6948 for (p = pStart; p < pEnd; ++p) { 6949 ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr); 6950 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 6951 else numbers[p-pStart] += shift; 6952 } 6953 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr); 6954 if (globalSize) { 6955 PetscLayout layout; 6956 ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr); 6957 ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr); 6958 ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr); 6959 } 6960 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 6961 ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr); 6962 PetscFunctionReturn(0); 6963 } 6964 6965 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 6966 { 6967 PetscInt cellHeight, cStart, cEnd, cMax; 6968 PetscErrorCode ierr; 6969 6970 PetscFunctionBegin; 6971 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 6972 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 6973 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 6974 if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax); 6975 ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr); 6976 PetscFunctionReturn(0); 6977 } 6978 6979 /*@ 6980 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 6981 6982 Input Parameter: 6983 . dm - The DMPlex object 6984 6985 Output Parameter: 6986 . globalCellNumbers - Global cell numbers for all cells on this process 6987 6988 Level: developer 6989 6990 .seealso DMPlexGetVertexNumbering() 6991 @*/ 6992 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 6993 { 6994 DM_Plex *mesh = (DM_Plex*) dm->data; 6995 PetscErrorCode ierr; 6996 6997 PetscFunctionBegin; 6998 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6999 if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);} 7000 *globalCellNumbers = mesh->globalCellNumbers; 7001 PetscFunctionReturn(0); 7002 } 7003 7004 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 7005 { 7006 PetscInt vStart, vEnd, vMax; 7007 PetscErrorCode ierr; 7008 7009 PetscFunctionBegin; 7010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7011 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 7012 ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr); 7013 if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax); 7014 ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr); 7015 PetscFunctionReturn(0); 7016 } 7017 7018 /*@ 7019 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 7020 7021 Input Parameter: 7022 . dm - The DMPlex object 7023 7024 Output Parameter: 7025 . globalVertexNumbers - Global vertex numbers for all vertices on this process 7026 7027 Level: developer 7028 7029 .seealso DMPlexGetCellNumbering() 7030 @*/ 7031 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 7032 { 7033 DM_Plex *mesh = (DM_Plex*) dm->data; 7034 PetscErrorCode ierr; 7035 7036 PetscFunctionBegin; 7037 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7038 if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);} 7039 *globalVertexNumbers = mesh->globalVertexNumbers; 7040 PetscFunctionReturn(0); 7041 } 7042 7043 /*@ 7044 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 7045 7046 Input Parameter: 7047 . dm - The DMPlex object 7048 7049 Output Parameter: 7050 . globalPointNumbers - Global numbers for all points on this process 7051 7052 Level: developer 7053 7054 .seealso DMPlexGetCellNumbering() 7055 @*/ 7056 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 7057 { 7058 IS nums[4]; 7059 PetscInt depths[4], gdepths[4], starts[4]; 7060 PetscInt depth, d, shift = 0; 7061 PetscErrorCode ierr; 7062 7063 PetscFunctionBegin; 7064 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7065 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 7066 /* For unstratified meshes use dim instead of depth */ 7067 if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);} 7068 for (d = 0; d <= depth; ++d) { 7069 PetscInt end; 7070 7071 depths[d] = depth-d; 7072 ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr); 7073 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 7074 } 7075 ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr); 7076 ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr); 7077 for (d = 0; d <= depth; ++d) { 7078 if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]); 7079 } 7080 for (d = 0; d <= depth; ++d) { 7081 PetscInt pStart, pEnd, gsize; 7082 7083 ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr); 7084 ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr); 7085 shift += gsize; 7086 } 7087 ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr); 7088 for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);} 7089 PetscFunctionReturn(0); 7090 } 7091 7092 7093 /*@ 7094 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 7095 7096 Input Parameter: 7097 . dm - The DMPlex object 7098 7099 Output Parameter: 7100 . ranks - The rank field 7101 7102 Options Database Keys: 7103 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 7104 7105 Level: intermediate 7106 7107 .seealso: DMView() 7108 @*/ 7109 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 7110 { 7111 DM rdm; 7112 PetscFE fe; 7113 PetscScalar *r; 7114 PetscMPIInt rank; 7115 PetscInt dim, cStart, cEnd, c; 7116 PetscErrorCode ierr; 7117 7118 PetscFunctionBeginUser; 7119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7120 PetscValidPointer(ranks, 2); 7121 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr); 7122 ierr = DMClone(dm, &rdm);CHKERRQ(ierr); 7123 ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr); 7124 ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);CHKERRQ(ierr); 7125 ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr); 7126 ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr); 7127 ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); 7128 ierr = DMCreateDS(rdm);CHKERRQ(ierr); 7129 ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr); 7130 ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr); 7131 ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr); 7132 ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr); 7133 for (c = cStart; c < cEnd; ++c) { 7134 PetscScalar *lr; 7135 7136 ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr); 7137 *lr = rank; 7138 } 7139 ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr); 7140 ierr = DMDestroy(&rdm);CHKERRQ(ierr); 7141 PetscFunctionReturn(0); 7142 } 7143 7144 /*@ 7145 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 7146 7147 Input Parameters: 7148 + dm - The DMPlex 7149 - label - The DMLabel 7150 7151 Output Parameter: 7152 . val - The label value field 7153 7154 Options Database Keys: 7155 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 7156 7157 Level: intermediate 7158 7159 .seealso: DMView() 7160 @*/ 7161 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 7162 { 7163 DM rdm; 7164 PetscFE fe; 7165 PetscScalar *v; 7166 PetscInt dim, cStart, cEnd, c; 7167 PetscErrorCode ierr; 7168 7169 PetscFunctionBeginUser; 7170 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7171 PetscValidPointer(label, 2); 7172 PetscValidPointer(val, 3); 7173 ierr = DMClone(dm, &rdm);CHKERRQ(ierr); 7174 ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr); 7175 ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr); 7176 ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr); 7177 ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr); 7178 ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); 7179 ierr = DMCreateDS(rdm);CHKERRQ(ierr); 7180 ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr); 7181 ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr); 7182 ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr); 7183 ierr = VecGetArray(*val, &v);CHKERRQ(ierr); 7184 for (c = cStart; c < cEnd; ++c) { 7185 PetscScalar *lv; 7186 PetscInt cval; 7187 7188 ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr); 7189 ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr); 7190 *lv = cval; 7191 } 7192 ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr); 7193 ierr = DMDestroy(&rdm);CHKERRQ(ierr); 7194 PetscFunctionReturn(0); 7195 } 7196 7197 /*@ 7198 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 7199 7200 Input Parameter: 7201 . dm - The DMPlex object 7202 7203 Notes: 7204 This is a useful diagnostic when creating meshes programmatically. 7205 7206 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7207 7208 Level: developer 7209 7210 .seealso: DMCreate(), DMSetFromOptions() 7211 @*/ 7212 PetscErrorCode DMPlexCheckSymmetry(DM dm) 7213 { 7214 PetscSection coneSection, supportSection; 7215 const PetscInt *cone, *support; 7216 PetscInt coneSize, c, supportSize, s; 7217 PetscInt pStart, pEnd, p, pp, csize, ssize; 7218 PetscBool storagecheck = PETSC_TRUE; 7219 PetscErrorCode ierr; 7220 7221 PetscFunctionBegin; 7222 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7223 ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr); 7224 ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr); 7225 /* Check that point p is found in the support of its cone points, and vice versa */ 7226 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 7227 for (p = pStart; p < pEnd; ++p) { 7228 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 7229 ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); 7230 for (c = 0; c < coneSize; ++c) { 7231 PetscBool dup = PETSC_FALSE; 7232 PetscInt d; 7233 for (d = c-1; d >= 0; --d) { 7234 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 7235 } 7236 ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr); 7237 ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr); 7238 for (s = 0; s < supportSize; ++s) { 7239 if (support[s] == p) break; 7240 } 7241 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 7242 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr); 7243 for (s = 0; s < coneSize; ++s) { 7244 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr); 7245 } 7246 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7247 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr); 7248 for (s = 0; s < supportSize; ++s) { 7249 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr); 7250 } 7251 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7252 if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]); 7253 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]); 7254 } 7255 } 7256 ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr); 7257 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 7258 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 7259 ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr); 7260 for (s = 0; s < supportSize; ++s) { 7261 ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr); 7262 ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr); 7263 for (c = 0; c < coneSize; ++c) { 7264 ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr); 7265 if (cone[c] != pp) { c = 0; break; } 7266 if (cone[c] == p) break; 7267 } 7268 if (c >= coneSize) { 7269 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr); 7270 for (c = 0; c < supportSize; ++c) { 7271 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr); 7272 } 7273 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7274 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr); 7275 for (c = 0; c < coneSize; ++c) { 7276 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr); 7277 } 7278 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7279 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]); 7280 } 7281 } 7282 } 7283 if (storagecheck) { 7284 ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr); 7285 ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr); 7286 if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize); 7287 } 7288 PetscFunctionReturn(0); 7289 } 7290 7291 /*@ 7292 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 7293 7294 Input Parameters: 7295 + dm - The DMPlex object 7296 - cellHeight - Normally 0 7297 7298 Notes: 7299 This is a useful diagnostic when creating meshes programmatically. 7300 Currently applicable only to homogeneous simplex or tensor meshes. 7301 7302 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7303 7304 Level: developer 7305 7306 .seealso: DMCreate(), DMSetFromOptions() 7307 @*/ 7308 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 7309 { 7310 PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c; 7311 PetscBool isSimplex = PETSC_FALSE; 7312 PetscErrorCode ierr; 7313 7314 PetscFunctionBegin; 7315 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7316 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 7317 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 7318 if (cStart < cEnd) { 7319 ierr = DMPlexGetConeSize(dm, cStart, &c);CHKERRQ(ierr); 7320 isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE; 7321 } 7322 switch (dim) { 7323 case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break; 7324 case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break; 7325 case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break; 7326 default: 7327 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim); 7328 } 7329 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 7330 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 7331 cMax = cMax >= 0 ? cMax : cEnd; 7332 for (c = cStart; c < cMax; ++c) { 7333 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 7334 7335 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7336 for (cl = 0; cl < closureSize*2; cl += 2) { 7337 const PetscInt p = closure[cl]; 7338 if ((p >= vStart) && (p < vEnd)) ++coneSize; 7339 } 7340 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7341 if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D", c, coneSize, numCorners); 7342 } 7343 for (c = cMax; c < cEnd; ++c) { 7344 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 7345 7346 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7347 for (cl = 0; cl < closureSize*2; cl += 2) { 7348 const PetscInt p = closure[cl]; 7349 if ((p >= vStart) && (p < vEnd)) ++coneSize; 7350 } 7351 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7352 if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has %D vertices > %D", c, coneSize, numHybridCorners); 7353 } 7354 PetscFunctionReturn(0); 7355 } 7356 7357 /*@ 7358 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 7359 7360 Not Collective 7361 7362 Input Parameters: 7363 + dm - The DMPlex object 7364 - cellHeight - Normally 0 7365 7366 Notes: 7367 This is a useful diagnostic when creating meshes programmatically. 7368 This routine is only relevant for meshes that are fully interpolated across all ranks. 7369 It will error out if a partially interpolated mesh is given on some rank. 7370 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 7371 7372 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7373 7374 Level: developer 7375 7376 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions() 7377 @*/ 7378 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 7379 { 7380 PetscInt pMax[4]; 7381 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 7382 PetscErrorCode ierr; 7383 DMPlexInterpolatedFlag interpEnum; 7384 7385 PetscFunctionBegin; 7386 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7387 ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr); 7388 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 7389 if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) { 7390 PetscMPIInt rank; 7391 MPI_Comm comm; 7392 7393 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 7394 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 7395 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank); 7396 } 7397 7398 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 7399 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 7400 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 7401 ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr); 7402 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 7403 ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr); 7404 for (c = cStart; c < cEnd; ++c) { 7405 const PetscInt *cone, *ornt, *faces; 7406 DMPolytopeType ct; 7407 PetscInt numFaces, faceSize, coneSize,f; 7408 PetscInt *closure = NULL, closureSize, cl, numCorners = 0; 7409 7410 if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue; 7411 ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr); 7412 ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr); 7413 ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr); 7414 ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr); 7415 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7416 for (cl = 0; cl < closureSize*2; cl += 2) { 7417 const PetscInt p = closure[cl]; 7418 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 7419 } 7420 ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr); 7421 if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces); 7422 for (f = 0; f < numFaces; ++f) { 7423 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 7424 7425 ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 7426 for (cl = 0; cl < fclosureSize*2; cl += 2) { 7427 const PetscInt p = fclosure[cl]; 7428 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 7429 } 7430 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); 7431 for (v = 0; v < fnumCorners; ++v) { 7432 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]); 7433 } 7434 ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 7435 } 7436 ierr = DMPlexRestoreFaces_Internal(dm, ct, &numFaces, &faceSize, &faces);CHKERRQ(ierr); 7437 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7438 } 7439 } 7440 PetscFunctionReturn(0); 7441 } 7442 7443 /*@ 7444 DMPlexCheckGeometry - Check the geometry of mesh cells 7445 7446 Input Parameter: 7447 . dm - The DMPlex object 7448 7449 Notes: 7450 This is a useful diagnostic when creating meshes programmatically. 7451 7452 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7453 7454 Level: developer 7455 7456 .seealso: DMCreate(), DMSetFromOptions() 7457 @*/ 7458 PetscErrorCode DMPlexCheckGeometry(DM dm) 7459 { 7460 PetscReal detJ, J[9], refVol = 1.0; 7461 PetscReal vol; 7462 PetscInt dim, depth, d, cStart, cEnd, c, cMax; 7463 PetscErrorCode ierr; 7464 7465 PetscFunctionBegin; 7466 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 7467 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 7468 for (d = 0; d < dim; ++d) refVol *= 2.0; 7469 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 7470 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 7471 cMax = cMax < 0 ? cEnd : cMax; 7472 for (c = cStart; c < cMax; ++c) { 7473 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr); 7474 if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ); 7475 ierr = PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr); 7476 if (depth > 1) { 7477 ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr); 7478 if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol); 7479 ierr = PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr); 7480 } 7481 } 7482 PetscFunctionReturn(0); 7483 } 7484 7485 /*@ 7486 DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex. 7487 7488 Input Parameters: 7489 . dm - The DMPlex object 7490 7491 Notes: 7492 This is mainly intended for debugging/testing purposes. 7493 It currently checks only meshes with no partition overlapping. 7494 7495 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7496 7497 Level: developer 7498 7499 .seealso: DMGetPointSF(), DMSetFromOptions() 7500 @*/ 7501 PetscErrorCode DMPlexCheckPointSF(DM dm) 7502 { 7503 PetscSF pointSF; 7504 PetscInt cellHeight, cStart, cEnd, l, nleaves, nroots, overlap; 7505 const PetscInt *locals, *rootdegree; 7506 PetscBool distributed; 7507 PetscErrorCode ierr; 7508 7509 PetscFunctionBegin; 7510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7511 ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr); 7512 ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr); 7513 if (!distributed) PetscFunctionReturn(0); 7514 ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr); 7515 if (overlap) { 7516 ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping"); 7517 PetscFunctionReturn(0); 7518 } 7519 if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached"); 7520 ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr); 7521 if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set"); 7522 ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr); 7523 ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr); 7524 7525 /* 1) check there are no faces in 2D, cells in 3D, in interface */ 7526 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 7527 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 7528 for (l = 0; l < nleaves; ++l) { 7529 const PetscInt point = locals[l]; 7530 7531 if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point); 7532 } 7533 7534 /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 7535 for (l = 0; l < nleaves; ++l) { 7536 const PetscInt point = locals[l]; 7537 const PetscInt *cone; 7538 PetscInt coneSize, c, idx; 7539 7540 ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr); 7541 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 7542 for (c = 0; c < coneSize; ++c) { 7543 if (!rootdegree[cone[c]]) { 7544 ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr); 7545 if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]); 7546 } 7547 } 7548 } 7549 PetscFunctionReturn(0); 7550 } 7551 7552 typedef struct cell_stats 7553 { 7554 PetscReal min, max, sum, squaresum; 7555 PetscInt count; 7556 } cell_stats_t; 7557 7558 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 7559 { 7560 PetscInt i, N = *len; 7561 7562 for (i = 0; i < N; i++) { 7563 cell_stats_t *A = (cell_stats_t *) a; 7564 cell_stats_t *B = (cell_stats_t *) b; 7565 7566 B->min = PetscMin(A->min,B->min); 7567 B->max = PetscMax(A->max,B->max); 7568 B->sum += A->sum; 7569 B->squaresum += A->squaresum; 7570 B->count += A->count; 7571 } 7572 } 7573 7574 /*@ 7575 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 7576 7577 Collective on dm 7578 7579 Input Parameters: 7580 + dm - The DMPlex object 7581 . output - If true, statistics will be displayed on stdout 7582 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 7583 7584 Notes: 7585 This is mainly intended for debugging/testing purposes. 7586 7587 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7588 7589 Level: developer 7590 7591 .seealso: DMSetFromOptions() 7592 @*/ 7593 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 7594 { 7595 DM dmCoarse; 7596 cell_stats_t stats, globalStats; 7597 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 7598 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 7599 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 7600 PetscInt cdim, cStart, cEnd, cMax, c, eStart, eEnd, count = 0; 7601 PetscMPIInt rank,size; 7602 PetscErrorCode ierr; 7603 7604 PetscFunctionBegin; 7605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7606 stats.min = PETSC_MAX_REAL; 7607 stats.max = PETSC_MIN_REAL; 7608 stats.sum = stats.squaresum = 0.; 7609 stats.count = 0; 7610 7611 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 7612 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 7613 ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr); 7614 ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr); 7615 ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr); 7616 ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr); 7617 ierr = DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);CHKERRQ(ierr); 7618 cMax = cMax < 0 ? cEnd : cMax; 7619 for (c = cStart; c < cMax; c++) { 7620 PetscInt i; 7621 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 7622 7623 ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr); 7624 if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c); 7625 for (i = 0; i < PetscSqr(cdim); ++i) { 7626 frobJ += J[i] * J[i]; 7627 frobInvJ += invJ[i] * invJ[i]; 7628 } 7629 cond2 = frobJ * frobInvJ; 7630 cond = PetscSqrtReal(cond2); 7631 7632 stats.min = PetscMin(stats.min,cond); 7633 stats.max = PetscMax(stats.max,cond); 7634 stats.sum += cond; 7635 stats.squaresum += cond2; 7636 stats.count++; 7637 if (output && cond > limit) { 7638 PetscSection coordSection; 7639 Vec coordsLocal; 7640 PetscScalar *coords = NULL; 7641 PetscInt Nv, d, clSize, cl, *closure = NULL; 7642 7643 ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr); 7644 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 7645 ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr); 7646 ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr); 7647 for (i = 0; i < Nv/cdim; ++i) { 7648 ierr = PetscSynchronizedPrintf(comm, " Vertex %D: (", i);CHKERRQ(ierr); 7649 for (d = 0; d < cdim; ++d) { 7650 if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);} 7651 ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr); 7652 } 7653 ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr); 7654 } 7655 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr); 7656 for (cl = 0; cl < clSize*2; cl += 2) { 7657 const PetscInt edge = closure[cl]; 7658 7659 if ((edge >= eStart) && (edge < eEnd)) { 7660 PetscReal len; 7661 7662 ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr); 7663 ierr = PetscSynchronizedPrintf(comm, " Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr); 7664 } 7665 } 7666 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr); 7667 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr); 7668 } 7669 } 7670 if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);} 7671 7672 if (size > 1) { 7673 PetscMPIInt blockLengths[2] = {4,1}; 7674 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 7675 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 7676 MPI_Op statReduce; 7677 7678 ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRQ(ierr); 7679 ierr = MPI_Type_commit(&statType);CHKERRQ(ierr); 7680 ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRQ(ierr); 7681 ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRQ(ierr); 7682 ierr = MPI_Op_free(&statReduce);CHKERRQ(ierr); 7683 ierr = MPI_Type_free(&statType);CHKERRQ(ierr); 7684 } else { 7685 ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr); 7686 } 7687 if (!rank) { 7688 count = globalStats.count; 7689 min = globalStats.min; 7690 max = globalStats.max; 7691 mean = globalStats.sum / globalStats.count; 7692 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 7693 } 7694 7695 if (output) { 7696 ierr = PetscPrintf(comm,"Mesh with %D cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double) min, (double) max, (double) mean, (double) stdev);CHKERRQ(ierr); 7697 } 7698 ierr = PetscFree2(J,invJ);CHKERRQ(ierr); 7699 7700 ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr); 7701 if (dmCoarse) { 7702 PetscBool isplex; 7703 7704 ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr); 7705 if (isplex) { 7706 ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr); 7707 } 7708 } 7709 PetscFunctionReturn(0); 7710 } 7711 7712 /* Pointwise interpolation 7713 Just code FEM for now 7714 u^f = I u^c 7715 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 7716 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 7717 I_{ij} = psi^f_i phi^c_j 7718 */ 7719 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 7720 { 7721 PetscSection gsc, gsf; 7722 PetscInt m, n; 7723 void *ctx; 7724 DM cdm; 7725 PetscBool regular, ismatis; 7726 PetscErrorCode ierr; 7727 7728 PetscFunctionBegin; 7729 ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr); 7730 ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr); 7731 ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr); 7732 ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr); 7733 7734 ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr); 7735 ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr); 7736 ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 7737 ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr); 7738 ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr); 7739 7740 ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr); 7741 ierr = DMPlexGetRegularRefinement(dmFine, ®ular);CHKERRQ(ierr); 7742 if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);} 7743 else {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);} 7744 ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr); 7745 if (scaling) { 7746 /* Use naive scaling */ 7747 ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr); 7748 } 7749 PetscFunctionReturn(0); 7750 } 7751 7752 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 7753 { 7754 PetscErrorCode ierr; 7755 VecScatter ctx; 7756 7757 PetscFunctionBegin; 7758 ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr); 7759 ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr); 7760 ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr); 7761 PetscFunctionReturn(0); 7762 } 7763 7764 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 7765 { 7766 PetscSection gsc, gsf; 7767 PetscInt m, n; 7768 void *ctx; 7769 DM cdm; 7770 PetscBool regular; 7771 PetscErrorCode ierr; 7772 7773 PetscFunctionBegin; 7774 ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr); 7775 ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr); 7776 ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr); 7777 ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr); 7778 7779 ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr); 7780 ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 7781 ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr); 7782 ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr); 7783 7784 ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr); 7785 ierr = DMPlexGetRegularRefinement(dmFine, ®ular);CHKERRQ(ierr); 7786 if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);} 7787 else {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);} 7788 ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr); 7789 PetscFunctionReturn(0); 7790 } 7791 7792 /*@ 7793 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 7794 7795 Input Parameter: 7796 . dm - The DMPlex object 7797 7798 Output Parameter: 7799 . regular - The flag 7800 7801 Level: intermediate 7802 7803 .seealso: DMPlexSetRegularRefinement() 7804 @*/ 7805 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 7806 { 7807 PetscFunctionBegin; 7808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7809 PetscValidPointer(regular, 2); 7810 *regular = ((DM_Plex *) dm->data)->regularRefinement; 7811 PetscFunctionReturn(0); 7812 } 7813 7814 /*@ 7815 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 7816 7817 Input Parameters: 7818 + dm - The DMPlex object 7819 - regular - The flag 7820 7821 Level: intermediate 7822 7823 .seealso: DMPlexGetRegularRefinement() 7824 @*/ 7825 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 7826 { 7827 PetscFunctionBegin; 7828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7829 ((DM_Plex *) dm->data)->regularRefinement = regular; 7830 PetscFunctionReturn(0); 7831 } 7832 7833 /* anchors */ 7834 /*@ 7835 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 7836 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints(). 7837 7838 not collective 7839 7840 Input Parameters: 7841 . dm - The DMPlex object 7842 7843 Output Parameters: 7844 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 7845 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 7846 7847 7848 Level: intermediate 7849 7850 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints() 7851 @*/ 7852 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 7853 { 7854 DM_Plex *plex = (DM_Plex *)dm->data; 7855 PetscErrorCode ierr; 7856 7857 PetscFunctionBegin; 7858 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7859 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);} 7860 if (anchorSection) *anchorSection = plex->anchorSection; 7861 if (anchorIS) *anchorIS = plex->anchorIS; 7862 PetscFunctionReturn(0); 7863 } 7864 7865 /*@ 7866 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 7867 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 7868 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 7869 7870 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 7871 DMGetConstraints() and filling in the entries in the constraint matrix. 7872 7873 collective on dm 7874 7875 Input Parameters: 7876 + dm - The DMPlex object 7877 . 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). 7878 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 7879 7880 The reference counts of anchorSection and anchorIS are incremented. 7881 7882 Level: intermediate 7883 7884 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints() 7885 @*/ 7886 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 7887 { 7888 DM_Plex *plex = (DM_Plex *)dm->data; 7889 PetscMPIInt result; 7890 PetscErrorCode ierr; 7891 7892 PetscFunctionBegin; 7893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7894 if (anchorSection) { 7895 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 7896 ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr); 7897 if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 7898 } 7899 if (anchorIS) { 7900 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 7901 ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr); 7902 if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 7903 } 7904 7905 ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr); 7906 ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr); 7907 plex->anchorSection = anchorSection; 7908 7909 ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr); 7910 ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr); 7911 plex->anchorIS = anchorIS; 7912 7913 #if defined(PETSC_USE_DEBUG) 7914 if (anchorIS && anchorSection) { 7915 PetscInt size, a, pStart, pEnd; 7916 const PetscInt *anchors; 7917 7918 ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr); 7919 ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr); 7920 ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr); 7921 for (a = 0; a < size; a++) { 7922 PetscInt p; 7923 7924 p = anchors[a]; 7925 if (p >= pStart && p < pEnd) { 7926 PetscInt dof; 7927 7928 ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr); 7929 if (dof) { 7930 PetscErrorCode ierr2; 7931 7932 ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2); 7933 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p); 7934 } 7935 } 7936 } 7937 ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr); 7938 } 7939 #endif 7940 /* reset the generic constraints */ 7941 ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr); 7942 PetscFunctionReturn(0); 7943 } 7944 7945 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 7946 { 7947 PetscSection anchorSection; 7948 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 7949 PetscErrorCode ierr; 7950 7951 PetscFunctionBegin; 7952 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7953 ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr); 7954 ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr); 7955 ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr); 7956 if (numFields) { 7957 PetscInt f; 7958 ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr); 7959 7960 for (f = 0; f < numFields; f++) { 7961 PetscInt numComp; 7962 7963 ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr); 7964 ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr); 7965 } 7966 } 7967 ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr); 7968 ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr); 7969 pStart = PetscMax(pStart,sStart); 7970 pEnd = PetscMin(pEnd,sEnd); 7971 pEnd = PetscMax(pStart,pEnd); 7972 ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr); 7973 for (p = pStart; p < pEnd; p++) { 7974 ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr); 7975 if (dof) { 7976 ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr); 7977 ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr); 7978 for (f = 0; f < numFields; f++) { 7979 ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr); 7980 ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr); 7981 } 7982 } 7983 } 7984 ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr); 7985 PetscFunctionReturn(0); 7986 } 7987 7988 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 7989 { 7990 PetscSection aSec; 7991 PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 7992 const PetscInt *anchors; 7993 PetscInt numFields, f; 7994 IS aIS; 7995 PetscErrorCode ierr; 7996 7997 PetscFunctionBegin; 7998 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7999 ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr); 8000 ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr); 8001 ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr); 8002 ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr); 8003 ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr); 8004 ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr); 8005 ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); 8006 /* cSec will be a subset of aSec and section */ 8007 ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr); 8008 ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr); 8009 i[0] = 0; 8010 ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr); 8011 for (p = pStart; p < pEnd; p++) { 8012 PetscInt rDof, rOff, r; 8013 8014 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 8015 if (!rDof) continue; 8016 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 8017 if (numFields) { 8018 for (f = 0; f < numFields; f++) { 8019 annz = 0; 8020 for (r = 0; r < rDof; r++) { 8021 a = anchors[rOff + r]; 8022 ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr); 8023 annz += aDof; 8024 } 8025 ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr); 8026 ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr); 8027 for (q = 0; q < dof; q++) { 8028 i[off + q + 1] = i[off + q] + annz; 8029 } 8030 } 8031 } 8032 else { 8033 annz = 0; 8034 for (q = 0; q < dof; q++) { 8035 a = anchors[off + q]; 8036 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 8037 annz += aDof; 8038 } 8039 ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr); 8040 ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr); 8041 for (q = 0; q < dof; q++) { 8042 i[off + q + 1] = i[off + q] + annz; 8043 } 8044 } 8045 } 8046 nnz = i[m]; 8047 ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr); 8048 offset = 0; 8049 for (p = pStart; p < pEnd; p++) { 8050 if (numFields) { 8051 for (f = 0; f < numFields; f++) { 8052 ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr); 8053 for (q = 0; q < dof; q++) { 8054 PetscInt rDof, rOff, r; 8055 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 8056 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 8057 for (r = 0; r < rDof; r++) { 8058 PetscInt s; 8059 8060 a = anchors[rOff + r]; 8061 ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr); 8062 ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr); 8063 for (s = 0; s < aDof; s++) { 8064 j[offset++] = aOff + s; 8065 } 8066 } 8067 } 8068 } 8069 } 8070 else { 8071 ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr); 8072 for (q = 0; q < dof; q++) { 8073 PetscInt rDof, rOff, r; 8074 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 8075 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 8076 for (r = 0; r < rDof; r++) { 8077 PetscInt s; 8078 8079 a = anchors[rOff + r]; 8080 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 8081 ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr); 8082 for (s = 0; s < aDof; s++) { 8083 j[offset++] = aOff + s; 8084 } 8085 } 8086 } 8087 } 8088 } 8089 ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr); 8090 ierr = PetscFree(i);CHKERRQ(ierr); 8091 ierr = PetscFree(j);CHKERRQ(ierr); 8092 ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); 8093 PetscFunctionReturn(0); 8094 } 8095 8096 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 8097 { 8098 DM_Plex *plex = (DM_Plex *)dm->data; 8099 PetscSection anchorSection, section, cSec; 8100 Mat cMat; 8101 PetscErrorCode ierr; 8102 8103 PetscFunctionBegin; 8104 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8105 ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr); 8106 if (anchorSection) { 8107 PetscInt Nf; 8108 8109 ierr = DMGetLocalSection(dm,§ion);CHKERRQ(ierr); 8110 ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr); 8111 ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr); 8112 ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr); 8113 if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);} 8114 ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr); 8115 ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr); 8116 ierr = MatDestroy(&cMat);CHKERRQ(ierr); 8117 } 8118 PetscFunctionReturn(0); 8119 } 8120 8121 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 8122 { 8123 IS subis; 8124 PetscSection section, subsection; 8125 PetscErrorCode ierr; 8126 8127 PetscFunctionBegin; 8128 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 8129 if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 8130 if (!subdm) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 8131 /* Create subdomain */ 8132 ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr); 8133 /* Create submodel */ 8134 ierr = DMPlexCreateSubpointIS(*subdm, &subis);CHKERRQ(ierr); 8135 ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr); 8136 ierr = ISDestroy(&subis);CHKERRQ(ierr); 8137 ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr); 8138 ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr); 8139 ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr); 8140 /* Create map from submodel to global model */ 8141 if (is) { 8142 PetscSection sectionGlobal, subsectionGlobal; 8143 IS spIS; 8144 const PetscInt *spmap; 8145 PetscInt *subIndices; 8146 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 8147 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 8148 8149 ierr = DMPlexCreateSubpointIS(*subdm, &spIS);CHKERRQ(ierr); 8150 ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr); 8151 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 8152 ierr = DMGetGlobalSection(dm, §ionGlobal);CHKERRQ(ierr); 8153 ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr); 8154 ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr); 8155 for (p = pStart; p < pEnd; ++p) { 8156 PetscInt gdof, pSubSize = 0; 8157 8158 ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr); 8159 if (gdof > 0) { 8160 for (f = 0; f < Nf; ++f) { 8161 PetscInt fdof, fcdof; 8162 8163 ierr = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr); 8164 ierr = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr); 8165 pSubSize += fdof-fcdof; 8166 } 8167 subSize += pSubSize; 8168 if (pSubSize) { 8169 if (bs < 0) { 8170 bs = pSubSize; 8171 } else if (bs != pSubSize) { 8172 /* Layout does not admit a pointwise block size */ 8173 bs = 1; 8174 } 8175 } 8176 } 8177 } 8178 /* Must have same blocksize on all procs (some might have no points) */ 8179 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 8180 ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr); 8181 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 8182 else {bs = bsMinMax[0];} 8183 ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr); 8184 for (p = pStart; p < pEnd; ++p) { 8185 PetscInt gdof, goff; 8186 8187 ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr); 8188 if (gdof > 0) { 8189 const PetscInt point = spmap[p]; 8190 8191 ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr); 8192 for (f = 0; f < Nf; ++f) { 8193 PetscInt fdof, fcdof, fc, f2, poff = 0; 8194 8195 /* Can get rid of this loop by storing field information in the global section */ 8196 for (f2 = 0; f2 < f; ++f2) { 8197 ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr); 8198 ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr); 8199 poff += fdof-fcdof; 8200 } 8201 ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr); 8202 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr); 8203 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 8204 subIndices[subOff] = goff+poff+fc; 8205 } 8206 } 8207 } 8208 } 8209 ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr); 8210 ierr = ISDestroy(&spIS);CHKERRQ(ierr); 8211 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr); 8212 if (bs > 1) { 8213 /* We need to check that the block size does not come from non-contiguous fields */ 8214 PetscInt i, j, set = 1; 8215 for (i = 0; i < subSize; i += bs) { 8216 for (j = 0; j < bs; ++j) { 8217 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 8218 } 8219 } 8220 if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);} 8221 } 8222 /* Attach nullspace */ 8223 for (f = 0; f < Nf; ++f) { 8224 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 8225 if ((*subdm)->nullspaceConstructors[f]) break; 8226 } 8227 if (f < Nf) { 8228 MatNullSpace nullSpace; 8229 8230 ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);CHKERRQ(ierr); 8231 ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr); 8232 ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr); 8233 } 8234 } 8235 PetscFunctionReturn(0); 8236 } 8237 8238 /*@ 8239 DMPlexMonitorThroughput - Report the cell throughput of FE integration 8240 8241 Input Parameter: 8242 - dm - The DM 8243 8244 Level: developer 8245 8246 Options Database Keys: 8247 . -dm_plex_monitor_throughput - Activate the monitor 8248 8249 .seealso: DMSetFromOptions(), DMPlexCreate() 8250 @*/ 8251 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 8252 { 8253 PetscStageLog stageLog; 8254 PetscLogEvent event; 8255 PetscLogStage stage; 8256 PetscEventPerfInfo eventInfo; 8257 PetscReal cellRate, flopRate; 8258 PetscInt cStart, cEnd, Nf, N; 8259 const char *name; 8260 PetscErrorCode ierr; 8261 8262 PetscFunctionBegin; 8263 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8264 #if defined(PETSC_USE_LOG) 8265 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 8266 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 8267 ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr); 8268 ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr); 8269 ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr); 8270 ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr); 8271 ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr); 8272 N = (cEnd - cStart)*Nf*eventInfo.count; 8273 flopRate = eventInfo.flops/eventInfo.time; 8274 cellRate = N/eventInfo.time; 8275 ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "DM (%s) FE Residual Integration: %D integrals %D reps\n Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, (double) cellRate, (double) (flopRate/1.e6));CHKERRQ(ierr); 8276 #else 8277 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 8278 #endif 8279 PetscFunctionReturn(0); 8280 } 8281