1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 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, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The DMPlex object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 35 { 36 DMPolytopeType ct; 37 PetscInt cStart, cEnd; 38 39 PetscFunctionBegin; 40 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 41 if (cEnd <= cStart) { 42 *simplex = PETSC_FALSE; 43 PetscFunctionReturn(0); 44 } 45 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 46 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 47 PetscFunctionReturn(0); 48 } 49 50 /*@ 51 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 52 53 Input Parameters: 54 + dm - The DMPlex object 55 - height - The cell height in the Plex, 0 is the default 56 57 Output Parameters: 58 + cStart - The first "normal" cell 59 - cEnd - The upper bound on "normal"" cells 60 61 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 62 63 Level: developer 64 65 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 66 @*/ 67 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 68 { 69 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 70 PetscInt cS, cE, c; 71 72 PetscFunctionBegin; 73 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 74 for (c = cS; c < cE; ++c) { 75 DMPolytopeType cct; 76 77 PetscCall(DMPlexGetCellType(dm, c, &cct)); 78 if ((PetscInt)cct < 0) break; 79 switch (cct) { 80 case DM_POLYTOPE_POINT: 81 case DM_POLYTOPE_SEGMENT: 82 case DM_POLYTOPE_TRIANGLE: 83 case DM_POLYTOPE_QUADRILATERAL: 84 case DM_POLYTOPE_TETRAHEDRON: 85 case DM_POLYTOPE_HEXAHEDRON: 86 ct = cct; 87 break; 88 default: 89 break; 90 } 91 if (ct != DM_POLYTOPE_UNKNOWN) break; 92 } 93 if (ct != DM_POLYTOPE_UNKNOWN) { 94 DMLabel ctLabel; 95 96 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 97 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 98 // Reset label for fast lookup 99 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 100 } 101 if (cStart) *cStart = cS; 102 if (cEnd) *cEnd = cE; 103 PetscFunctionReturn(0); 104 } 105 106 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 107 { 108 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 109 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 110 111 PetscFunctionBegin; 112 *ft = PETSC_VTK_INVALID; 113 PetscCall(DMGetCoordinateDim(dm, &cdim)); 114 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 115 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 116 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 117 if (field >= 0) { 118 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 119 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 120 } else { 121 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 122 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 123 } 124 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 125 if (globalvcdof[0]) { 126 *sStart = vStart; 127 *sEnd = vEnd; 128 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 129 else *ft = PETSC_VTK_POINT_FIELD; 130 } else if (globalvcdof[1]) { 131 *sStart = cStart; 132 *sEnd = cEnd; 133 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 134 else *ft = PETSC_VTK_CELL_FIELD; 135 } else { 136 if (field >= 0) { 137 const char *fieldname; 138 139 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 140 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 141 } else { 142 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 143 } 144 } 145 PetscFunctionReturn(0); 146 } 147 148 /*@ 149 DMPlexVecView1D - Plot many 1D solutions on the same line graph 150 151 Collective on dm 152 153 Input Parameters: 154 + dm - The DMPlex 155 . n - The number of vectors 156 . u - The array of local vectors 157 - viewer - The Draw viewer 158 159 Level: advanced 160 161 .seealso: `VecViewFromOptions()`, `VecView()` 162 @*/ 163 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 164 { 165 PetscDS ds; 166 PetscDraw draw = NULL; 167 PetscDrawLG lg; 168 Vec coordinates; 169 const PetscScalar *coords, **sol; 170 PetscReal *vals; 171 PetscInt *Nc; 172 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 173 char **names; 174 175 PetscFunctionBegin; 176 PetscCall(DMGetDS(dm, &ds)); 177 PetscCall(PetscDSGetNumFields(ds, &Nf)); 178 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 179 PetscCall(PetscDSGetComponents(ds, &Nc)); 180 181 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 182 if (!draw) PetscFunctionReturn(0); 183 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 184 185 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 186 for (i = 0, l = 0; i < n; ++i) { 187 const char *vname; 188 189 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 190 for (f = 0; f < Nf; ++f) { 191 PetscObject disc; 192 const char *fname; 193 char tmpname[PETSC_MAX_PATH_LEN]; 194 195 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 196 /* TODO Create names for components */ 197 for (c = 0; c < Nc[f]; ++c, ++l) { 198 PetscCall(PetscObjectGetName(disc, &fname)); 199 PetscCall(PetscStrcpy(tmpname, vname)); 200 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 201 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 202 PetscCall(PetscStrallocpy(tmpname, &names[l])); 203 } 204 } 205 } 206 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 207 /* Just add P_1 support for now */ 208 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 209 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 210 PetscCall(VecGetArrayRead(coordinates, &coords)); 211 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 212 for (v = vStart; v < vEnd; ++v) { 213 PetscScalar *x, *svals; 214 215 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 216 for (i = 0; i < n; ++i) { 217 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 218 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 219 } 220 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 221 } 222 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 223 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 224 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 225 PetscCall(PetscFree3(sol, names, vals)); 226 227 PetscCall(PetscDrawLGDraw(lg)); 228 PetscCall(PetscDrawLGDestroy(&lg)); 229 PetscFunctionReturn(0); 230 } 231 232 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 233 { 234 DM dm; 235 236 PetscFunctionBegin; 237 PetscCall(VecGetDM(u, &dm)); 238 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 239 PetscFunctionReturn(0); 240 } 241 242 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 243 { 244 DM dm; 245 PetscSection s; 246 PetscDraw draw, popup; 247 DM cdm; 248 PetscSection coordSection; 249 Vec coordinates; 250 const PetscScalar *coords, *array; 251 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 252 PetscReal vbound[2], time; 253 PetscBool flg; 254 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 255 const char *name; 256 char title[PETSC_MAX_PATH_LEN]; 257 258 PetscFunctionBegin; 259 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 260 PetscCall(VecGetDM(v, &dm)); 261 PetscCall(DMGetCoordinateDim(dm, &dim)); 262 PetscCall(DMGetLocalSection(dm, &s)); 263 PetscCall(PetscSectionGetNumFields(s, &Nf)); 264 PetscCall(DMGetCoarsenLevel(dm, &level)); 265 PetscCall(DMGetCoordinateDM(dm, &cdm)); 266 PetscCall(DMGetLocalSection(cdm, &coordSection)); 267 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 268 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 269 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 270 271 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 272 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 273 274 PetscCall(VecGetLocalSize(coordinates, &N)); 275 PetscCall(VecGetArrayRead(coordinates, &coords)); 276 for (c = 0; c < N; c += dim) { 277 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 278 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 279 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 280 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 281 } 282 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 283 PetscCall(PetscDrawClear(draw)); 284 285 /* Could implement something like DMDASelectFields() */ 286 for (f = 0; f < Nf; ++f) { 287 DM fdm = dm; 288 Vec fv = v; 289 IS fis; 290 char prefix[PETSC_MAX_PATH_LEN]; 291 const char *fname; 292 293 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 294 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 295 296 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 297 else prefix[0] = '\0'; 298 if (Nf > 1) { 299 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 300 PetscCall(VecGetSubVector(v, fis, &fv)); 301 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 302 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 303 } 304 for (comp = 0; comp < Nc; ++comp, ++w) { 305 PetscInt nmax = 2; 306 307 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 308 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 309 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 310 PetscCall(PetscDrawSetTitle(draw, title)); 311 312 /* TODO Get max and min only for this component */ 313 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 314 if (!flg) { 315 PetscCall(VecMin(fv, NULL, &vbound[0])); 316 PetscCall(VecMax(fv, NULL, &vbound[1])); 317 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 318 } 319 PetscCall(PetscDrawGetPopup(draw, &popup)); 320 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 321 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 322 323 PetscCall(VecGetArrayRead(fv, &array)); 324 for (c = cStart; c < cEnd; ++c) { 325 PetscScalar *coords = NULL, *a = NULL; 326 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 327 328 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 329 if (a) { 330 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 331 color[1] = color[2] = color[3] = color[0]; 332 } else { 333 PetscScalar *vals = NULL; 334 PetscInt numVals, va; 335 336 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 337 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 338 switch (numVals / Nc) { 339 case 3: /* P1 Triangle */ 340 case 4: /* P1 Quadrangle */ 341 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 342 break; 343 case 6: /* P2 Triangle */ 344 case 8: /* P2 Quadrangle */ 345 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 346 break; 347 default: 348 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 349 } 350 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 351 } 352 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 353 switch (numCoords) { 354 case 6: 355 case 12: /* Localized triangle */ 356 PetscCall(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])); 357 break; 358 case 8: 359 case 16: /* Localized quadrilateral */ 360 PetscCall(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])); 361 PetscCall(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])); 362 break; 363 default: 364 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 365 } 366 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 367 } 368 PetscCall(VecRestoreArrayRead(fv, &array)); 369 PetscCall(PetscDrawFlush(draw)); 370 PetscCall(PetscDrawPause(draw)); 371 PetscCall(PetscDrawSave(draw)); 372 } 373 if (Nf > 1) { 374 PetscCall(VecRestoreSubVector(v, fis, &fv)); 375 PetscCall(ISDestroy(&fis)); 376 PetscCall(DMDestroy(&fdm)); 377 } 378 } 379 PetscFunctionReturn(0); 380 } 381 382 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 383 { 384 DM dm; 385 PetscDraw draw; 386 PetscInt dim; 387 PetscBool isnull; 388 389 PetscFunctionBegin; 390 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 391 PetscCall(PetscDrawIsNull(draw, &isnull)); 392 if (isnull) PetscFunctionReturn(0); 393 394 PetscCall(VecGetDM(v, &dm)); 395 PetscCall(DMGetCoordinateDim(dm, &dim)); 396 switch (dim) { 397 case 1: 398 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 399 break; 400 case 2: 401 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 402 break; 403 default: 404 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 405 } 406 PetscFunctionReturn(0); 407 } 408 409 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 410 { 411 DM dm; 412 Vec locv; 413 const char *name; 414 PetscSection section; 415 PetscInt pStart, pEnd; 416 PetscInt numFields; 417 PetscViewerVTKFieldType ft; 418 419 PetscFunctionBegin; 420 PetscCall(VecGetDM(v, &dm)); 421 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 422 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 423 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 424 PetscCall(VecCopy(v, locv)); 425 PetscCall(DMGetLocalSection(dm, §ion)); 426 PetscCall(PetscSectionGetNumFields(section, &numFields)); 427 if (!numFields) { 428 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 429 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 430 } else { 431 PetscInt f; 432 433 for (f = 0; f < numFields; f++) { 434 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 435 if (ft == PETSC_VTK_INVALID) continue; 436 PetscCall(PetscObjectReference((PetscObject)locv)); 437 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 438 } 439 PetscCall(VecDestroy(&locv)); 440 } 441 PetscFunctionReturn(0); 442 } 443 444 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 445 { 446 DM dm; 447 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 448 449 PetscFunctionBegin; 450 PetscCall(VecGetDM(v, &dm)); 451 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 452 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 453 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 454 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 455 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 456 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 457 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 458 PetscInt i, numFields; 459 PetscObject fe; 460 PetscBool fem = PETSC_FALSE; 461 Vec locv = v; 462 const char *name; 463 PetscInt step; 464 PetscReal time; 465 466 PetscCall(DMGetNumFields(dm, &numFields)); 467 for (i = 0; i < numFields; i++) { 468 PetscCall(DMGetField(dm, i, NULL, &fe)); 469 if (fe->classid == PETSCFE_CLASSID) { 470 fem = PETSC_TRUE; 471 break; 472 } 473 } 474 if (fem) { 475 PetscObject isZero; 476 477 PetscCall(DMGetLocalVector(dm, &locv)); 478 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 479 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 480 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 481 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 482 PetscCall(VecCopy(v, locv)); 483 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 484 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 485 } 486 if (isvtk) { 487 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 488 } else if (ishdf5) { 489 #if defined(PETSC_HAVE_HDF5) 490 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 491 #else 492 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 493 #endif 494 } else if (isdraw) { 495 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 496 } else if (isglvis) { 497 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 498 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 499 PetscCall(VecView_GLVis(locv, viewer)); 500 } else if (iscgns) { 501 #if defined(PETSC_HAVE_CGNS) 502 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 503 #else 504 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 505 #endif 506 } 507 if (fem) { 508 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 509 PetscCall(DMRestoreLocalVector(dm, &locv)); 510 } 511 } else { 512 PetscBool isseq; 513 514 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 515 if (isseq) PetscCall(VecView_Seq(v, viewer)); 516 else PetscCall(VecView_MPI(v, viewer)); 517 } 518 PetscFunctionReturn(0); 519 } 520 521 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 522 { 523 DM dm; 524 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 525 526 PetscFunctionBegin; 527 PetscCall(VecGetDM(v, &dm)); 528 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 529 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 530 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 531 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 532 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 533 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 534 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 535 if (isvtk || isdraw || isglvis || iscgns) { 536 Vec locv; 537 PetscObject isZero; 538 const char *name; 539 540 PetscCall(DMGetLocalVector(dm, &locv)); 541 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 542 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 543 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 544 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 545 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 546 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 547 PetscCall(VecView_Plex_Local(locv, viewer)); 548 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 549 PetscCall(DMRestoreLocalVector(dm, &locv)); 550 } else if (ishdf5) { 551 #if defined(PETSC_HAVE_HDF5) 552 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 553 #else 554 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 555 #endif 556 } else if (isexodusii) { 557 #if defined(PETSC_HAVE_EXODUSII) 558 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 559 #else 560 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 561 #endif 562 } else { 563 PetscBool isseq; 564 565 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 566 if (isseq) PetscCall(VecView_Seq(v, viewer)); 567 else PetscCall(VecView_MPI(v, viewer)); 568 } 569 PetscFunctionReturn(0); 570 } 571 572 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 573 { 574 DM dm; 575 MPI_Comm comm; 576 PetscViewerFormat format; 577 Vec v; 578 PetscBool isvtk, ishdf5; 579 580 PetscFunctionBegin; 581 PetscCall(VecGetDM(originalv, &dm)); 582 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 583 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 584 PetscCall(PetscViewerGetFormat(viewer, &format)); 585 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 586 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 587 if (format == PETSC_VIEWER_NATIVE) { 588 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 589 /* this need a better fix */ 590 if (dm->useNatural) { 591 if (dm->sfNatural) { 592 const char *vecname; 593 PetscInt n, nroots; 594 595 PetscCall(VecGetLocalSize(originalv, &n)); 596 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 597 if (n == nroots) { 598 PetscCall(DMGetGlobalVector(dm, &v)); 599 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 600 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 601 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 602 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 603 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 604 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 605 } else v = originalv; 606 } else v = originalv; 607 608 if (ishdf5) { 609 #if defined(PETSC_HAVE_HDF5) 610 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 611 #else 612 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 613 #endif 614 } else if (isvtk) { 615 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool ishdf5; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 if (ishdf5) { 637 DM dmBC; 638 Vec gv; 639 const char *name; 640 641 PetscCall(DMGetOutputDM(dm, &dmBC)); 642 PetscCall(DMGetGlobalVector(dmBC, &gv)); 643 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 644 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 645 PetscCall(VecLoad_Default(gv, viewer)); 646 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 647 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 648 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 649 } else PetscCall(VecLoad_Default(v, viewer)); 650 PetscFunctionReturn(0); 651 } 652 653 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 654 { 655 DM dm; 656 PetscBool ishdf5, isexodusii; 657 658 PetscFunctionBegin; 659 PetscCall(VecGetDM(v, &dm)); 660 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 661 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 662 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 663 if (ishdf5) { 664 #if defined(PETSC_HAVE_HDF5) 665 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 666 #else 667 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 668 #endif 669 } else if (isexodusii) { 670 #if defined(PETSC_HAVE_EXODUSII) 671 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 672 #else 673 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 674 #endif 675 } else PetscCall(VecLoad_Default(v, viewer)); 676 PetscFunctionReturn(0); 677 } 678 679 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 680 { 681 DM dm; 682 PetscViewerFormat format; 683 PetscBool ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 688 PetscCall(PetscViewerGetFormat(viewer, &format)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 690 if (format == PETSC_VIEWER_NATIVE) { 691 if (dm->useNatural) { 692 if (dm->sfNatural) { 693 if (ishdf5) { 694 #if defined(PETSC_HAVE_HDF5) 695 Vec v; 696 const char *vecname; 697 698 PetscCall(DMGetGlobalVector(dm, &v)); 699 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 700 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 701 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 702 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 703 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 704 PetscCall(DMRestoreGlobalVector(dm, &v)); 705 #else 706 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 707 #endif 708 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 709 } 710 } else PetscCall(VecLoad_Default(originalv, viewer)); 711 } 712 PetscFunctionReturn(0); 713 } 714 715 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 716 { 717 PetscSection coordSection; 718 Vec coordinates; 719 DMLabel depthLabel, celltypeLabel; 720 const char *name[4]; 721 const PetscScalar *a; 722 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 723 724 PetscFunctionBegin; 725 PetscCall(DMGetDimension(dm, &dim)); 726 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 727 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 728 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 729 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 730 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 731 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 732 PetscCall(VecGetArrayRead(coordinates, &a)); 733 name[0] = "vertex"; 734 name[1] = "edge"; 735 name[dim - 1] = "face"; 736 name[dim] = "cell"; 737 for (c = cStart; c < cEnd; ++c) { 738 PetscInt *closure = NULL; 739 PetscInt closureSize, cl, ct; 740 741 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 742 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 743 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 744 PetscCall(PetscViewerASCIIPushTab(viewer)); 745 for (cl = 0; cl < closureSize * 2; cl += 2) { 746 PetscInt point = closure[cl], depth, dof, off, d, p; 747 748 if ((point < pStart) || (point >= pEnd)) continue; 749 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 750 if (!dof) continue; 751 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 752 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 753 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 754 for (p = 0; p < dof / dim; ++p) { 755 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 756 for (d = 0; d < dim; ++d) { 757 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 758 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 759 } 760 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 761 } 762 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 763 } 764 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 765 PetscCall(PetscViewerASCIIPopTab(viewer)); 766 } 767 PetscCall(VecRestoreArrayRead(coordinates, &a)); 768 PetscFunctionReturn(0); 769 } 770 771 typedef enum { 772 CS_CARTESIAN, 773 CS_POLAR, 774 CS_CYLINDRICAL, 775 CS_SPHERICAL 776 } CoordSystem; 777 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 778 779 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 780 { 781 PetscInt i; 782 783 PetscFunctionBegin; 784 if (dim > 3) { 785 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 786 } else { 787 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 788 789 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 790 switch (cs) { 791 case CS_CARTESIAN: 792 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 793 break; 794 case CS_POLAR: 795 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 796 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 797 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 798 break; 799 case CS_CYLINDRICAL: 800 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 801 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 802 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 803 trcoords[2] = coords[2]; 804 break; 805 case CS_SPHERICAL: 806 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 807 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 808 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 809 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 810 break; 811 } 812 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 813 } 814 PetscFunctionReturn(0); 815 } 816 817 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 818 { 819 DM_Plex *mesh = (DM_Plex *)dm->data; 820 DM cdm, cdmCell; 821 PetscSection coordSection, coordSectionCell; 822 Vec coordinates, coordinatesCell; 823 PetscViewerFormat format; 824 825 PetscFunctionBegin; 826 PetscCall(PetscViewerGetFormat(viewer, &format)); 827 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 828 const char *name; 829 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 830 PetscInt pStart, pEnd, p, numLabels, l; 831 PetscMPIInt rank, size; 832 833 PetscCall(DMGetCoordinateDM(dm, &cdm)); 834 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 835 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 836 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 837 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 838 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 839 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 840 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 841 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 842 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 843 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 844 PetscCall(DMGetDimension(dm, &dim)); 845 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 846 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 847 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 848 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 849 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 850 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 851 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 852 for (p = pStart; p < pEnd; ++p) { 853 PetscInt dof, off, s; 854 855 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 856 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 857 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 858 } 859 PetscCall(PetscViewerFlush(viewer)); 860 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 861 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 862 for (p = pStart; p < pEnd; ++p) { 863 PetscInt dof, off, c; 864 865 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 866 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 867 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 868 } 869 PetscCall(PetscViewerFlush(viewer)); 870 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 871 if (coordSection && coordinates) { 872 CoordSystem cs = CS_CARTESIAN; 873 const PetscScalar *array, *arrayCell = NULL; 874 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 875 PetscMPIInt rank; 876 const char *name; 877 878 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 879 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 880 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 881 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 882 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 883 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 884 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 885 pStart = PetscMin(pvStart, pcStart); 886 pEnd = PetscMax(pvEnd, pcEnd); 887 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 888 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 889 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 890 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 891 892 PetscCall(VecGetArrayRead(coordinates, &array)); 893 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 894 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 895 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 896 for (p = pStart; p < pEnd; ++p) { 897 PetscInt dof, off; 898 899 if (p >= pvStart && p < pvEnd) { 900 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 901 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 902 if (dof) { 903 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 904 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 905 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 906 } 907 } 908 if (cdmCell && p >= pcStart && p < pcEnd) { 909 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 910 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 911 if (dof) { 912 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 913 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 914 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 915 } 916 } 917 } 918 PetscCall(PetscViewerFlush(viewer)); 919 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 920 PetscCall(VecRestoreArrayRead(coordinates, &array)); 921 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 922 } 923 PetscCall(DMGetNumLabels(dm, &numLabels)); 924 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 925 for (l = 0; l < numLabels; ++l) { 926 DMLabel label; 927 PetscBool isdepth; 928 const char *name; 929 930 PetscCall(DMGetLabelName(dm, l, &name)); 931 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 932 if (isdepth) continue; 933 PetscCall(DMGetLabel(dm, name, &label)); 934 PetscCall(DMLabelView(label, viewer)); 935 } 936 if (size > 1) { 937 PetscSF sf; 938 939 PetscCall(DMGetPointSF(dm, &sf)); 940 PetscCall(PetscSFView(sf, viewer)); 941 } 942 PetscCall(PetscViewerFlush(viewer)); 943 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 944 const char *name, *color; 945 const char *defcolors[3] = {"gray", "orange", "green"}; 946 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 947 char lname[PETSC_MAX_PATH_LEN]; 948 PetscReal scale = 2.0; 949 PetscReal tikzscale = 1.0; 950 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 951 double tcoords[3]; 952 PetscScalar *coords; 953 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 954 PetscMPIInt rank, size; 955 char **names, **colors, **lcolors; 956 PetscBool flg, lflg; 957 PetscBT wp = NULL; 958 PetscInt pEnd, pStart; 959 960 PetscCall(DMGetCoordinateDM(dm, &cdm)); 961 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 962 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 963 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 964 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 965 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 966 PetscCall(DMGetDimension(dm, &dim)); 967 PetscCall(DMPlexGetDepth(dm, &depth)); 968 PetscCall(DMGetNumLabels(dm, &numLabels)); 969 numLabels = PetscMax(numLabels, 10); 970 numColors = 10; 971 numLColors = 10; 972 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 973 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 974 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 975 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 976 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 977 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 978 n = 4; 979 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 980 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 981 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 982 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 983 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 984 if (!useLabels) numLabels = 0; 985 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 986 if (!useColors) { 987 numColors = 3; 988 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 989 } 990 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 991 if (!useColors) { 992 numLColors = 4; 993 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 994 } 995 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 996 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 997 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 998 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 999 if (depth < dim) plotEdges = PETSC_FALSE; 1000 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1001 1002 /* filter points with labelvalue != labeldefaultvalue */ 1003 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1004 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1005 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1006 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1007 if (lflg) { 1008 DMLabel lbl; 1009 1010 PetscCall(DMGetLabel(dm, lname, &lbl)); 1011 if (lbl) { 1012 PetscInt val, defval; 1013 1014 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1015 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1016 for (c = pStart; c < pEnd; c++) { 1017 PetscInt *closure = NULL; 1018 PetscInt closureSize; 1019 1020 PetscCall(DMLabelGetValue(lbl, c, &val)); 1021 if (val == defval) continue; 1022 1023 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1024 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1025 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1026 } 1027 } 1028 } 1029 1030 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1031 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1032 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1033 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1034 \\documentclass[tikz]{standalone}\n\n\ 1035 \\usepackage{pgflibraryshapes}\n\ 1036 \\usetikzlibrary{backgrounds}\n\ 1037 \\usetikzlibrary{arrows}\n\ 1038 \\begin{document}\n")); 1039 if (size > 1) { 1040 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1041 for (p = 0; p < size; ++p) { 1042 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1043 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1044 } 1045 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1046 } 1047 if (drawHasse) { 1048 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1049 1050 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1051 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1055 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1058 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1059 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1060 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1061 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1062 } 1063 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1064 1065 /* Plot vertices */ 1066 PetscCall(VecGetArray(coordinates, &coords)); 1067 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1068 for (v = vStart; v < vEnd; ++v) { 1069 PetscInt off, dof, d; 1070 PetscBool isLabeled = PETSC_FALSE; 1071 1072 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1073 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1074 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1075 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1076 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1077 for (d = 0; d < dof; ++d) { 1078 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1079 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1080 } 1081 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1082 if (dim == 3) { 1083 PetscReal tmp = tcoords[1]; 1084 tcoords[1] = tcoords[2]; 1085 tcoords[2] = -tmp; 1086 } 1087 for (d = 0; d < dof; ++d) { 1088 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1089 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1090 } 1091 if (drawHasse) color = colors[0 % numColors]; 1092 else color = colors[rank % numColors]; 1093 for (l = 0; l < numLabels; ++l) { 1094 PetscInt val; 1095 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1096 if (val >= 0) { 1097 color = lcolors[l % numLColors]; 1098 isLabeled = PETSC_TRUE; 1099 break; 1100 } 1101 } 1102 if (drawNumbers[0]) { 1103 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1104 } else if (drawColors[0]) { 1105 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1106 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1107 } 1108 PetscCall(VecRestoreArray(coordinates, &coords)); 1109 PetscCall(PetscViewerFlush(viewer)); 1110 /* Plot edges */ 1111 if (plotEdges) { 1112 PetscCall(VecGetArray(coordinates, &coords)); 1113 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1114 for (e = eStart; e < eEnd; ++e) { 1115 const PetscInt *cone; 1116 PetscInt coneSize, offA, offB, dof, d; 1117 1118 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1119 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1120 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1121 PetscCall(DMPlexGetCone(dm, e, &cone)); 1122 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1123 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1124 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1125 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1126 for (d = 0; d < dof; ++d) { 1127 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1128 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1129 } 1130 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1131 if (dim == 3) { 1132 PetscReal tmp = tcoords[1]; 1133 tcoords[1] = tcoords[2]; 1134 tcoords[2] = -tmp; 1135 } 1136 for (d = 0; d < dof; ++d) { 1137 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1138 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1139 } 1140 if (drawHasse) color = colors[1 % numColors]; 1141 else color = colors[rank % numColors]; 1142 for (l = 0; l < numLabels; ++l) { 1143 PetscInt val; 1144 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1145 if (val >= 0) { 1146 color = lcolors[l % numLColors]; 1147 break; 1148 } 1149 } 1150 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1151 } 1152 PetscCall(VecRestoreArray(coordinates, &coords)); 1153 PetscCall(PetscViewerFlush(viewer)); 1154 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1155 } 1156 /* Plot cells */ 1157 if (dim == 3 || !drawNumbers[1]) { 1158 for (e = eStart; e < eEnd; ++e) { 1159 const PetscInt *cone; 1160 1161 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1162 color = colors[rank % numColors]; 1163 for (l = 0; l < numLabels; ++l) { 1164 PetscInt val; 1165 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1166 if (val >= 0) { 1167 color = lcolors[l % numLColors]; 1168 break; 1169 } 1170 } 1171 PetscCall(DMPlexGetCone(dm, e, &cone)); 1172 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1173 } 1174 } else { 1175 DMPolytopeType ct; 1176 1177 /* Drawing a 2D polygon */ 1178 for (c = cStart; c < cEnd; ++c) { 1179 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1180 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1181 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1182 const PetscInt *cone; 1183 PetscInt coneSize, e; 1184 1185 PetscCall(DMPlexGetCone(dm, c, &cone)); 1186 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1187 for (e = 0; e < coneSize; ++e) { 1188 const PetscInt *econe; 1189 1190 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1191 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1192 } 1193 } else { 1194 PetscInt *closure = NULL; 1195 PetscInt closureSize, Nv = 0, v; 1196 1197 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1198 for (p = 0; p < closureSize * 2; p += 2) { 1199 const PetscInt point = closure[p]; 1200 1201 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1202 } 1203 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1204 for (v = 0; v <= Nv; ++v) { 1205 const PetscInt vertex = closure[v % Nv]; 1206 1207 if (v > 0) { 1208 if (plotEdges) { 1209 const PetscInt *edge; 1210 PetscInt endpoints[2], ne; 1211 1212 endpoints[0] = closure[v - 1]; 1213 endpoints[1] = vertex; 1214 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1215 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1216 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1217 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1218 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1219 } 1220 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1221 } 1222 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1223 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 } 1225 } 1226 } 1227 for (c = cStart; c < cEnd; ++c) { 1228 double ccoords[3] = {0.0, 0.0, 0.0}; 1229 PetscBool isLabeled = PETSC_FALSE; 1230 PetscScalar *cellCoords = NULL; 1231 const PetscScalar *array; 1232 PetscInt numCoords, cdim, d; 1233 PetscBool isDG; 1234 1235 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1236 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1237 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1238 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1239 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1240 for (p = 0; p < numCoords / cdim; ++p) { 1241 for (d = 0; d < cdim; ++d) { 1242 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1243 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1244 } 1245 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1246 if (cdim == 3) { 1247 PetscReal tmp = tcoords[1]; 1248 tcoords[1] = tcoords[2]; 1249 tcoords[2] = -tmp; 1250 } 1251 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1252 } 1253 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1254 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1255 for (d = 0; d < cdim; ++d) { 1256 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1257 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1258 } 1259 if (drawHasse) color = colors[depth % numColors]; 1260 else color = colors[rank % numColors]; 1261 for (l = 0; l < numLabels; ++l) { 1262 PetscInt val; 1263 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1264 if (val >= 0) { 1265 color = lcolors[l % numLColors]; 1266 isLabeled = PETSC_TRUE; 1267 break; 1268 } 1269 } 1270 if (drawNumbers[dim]) { 1271 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1272 } else if (drawColors[dim]) { 1273 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1274 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1275 } 1276 if (drawHasse) { 1277 color = colors[depth % numColors]; 1278 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1279 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1280 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1281 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1282 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1283 1284 color = colors[1 % numColors]; 1285 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1286 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1287 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1288 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1289 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1290 1291 color = colors[0 % numColors]; 1292 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1293 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1294 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1295 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1296 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1297 1298 for (p = pStart; p < pEnd; ++p) { 1299 const PetscInt *cone; 1300 PetscInt coneSize, cp; 1301 1302 PetscCall(DMPlexGetCone(dm, p, &cone)); 1303 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1304 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1305 } 1306 } 1307 PetscCall(PetscViewerFlush(viewer)); 1308 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1309 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1310 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1311 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1312 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1313 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1314 PetscCall(PetscFree3(names, colors, lcolors)); 1315 PetscCall(PetscBTDestroy(&wp)); 1316 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1317 Vec cown, acown; 1318 VecScatter sct; 1319 ISLocalToGlobalMapping g2l; 1320 IS gid, acis; 1321 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1322 MPI_Group ggroup, ngroup; 1323 PetscScalar *array, nid; 1324 const PetscInt *idxs; 1325 PetscInt *idxs2, *start, *adjacency, *work; 1326 PetscInt64 lm[3], gm[3]; 1327 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1328 PetscMPIInt d1, d2, rank; 1329 1330 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1331 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1332 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1333 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1334 #endif 1335 if (ncomm != MPI_COMM_NULL) { 1336 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1337 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1338 d1 = 0; 1339 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1340 nid = d2; 1341 PetscCallMPI(MPI_Group_free(&ggroup)); 1342 PetscCallMPI(MPI_Group_free(&ngroup)); 1343 PetscCallMPI(MPI_Comm_free(&ncomm)); 1344 } else nid = 0.0; 1345 1346 /* Get connectivity */ 1347 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1348 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1349 1350 /* filter overlapped local cells */ 1351 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1352 PetscCall(ISGetIndices(gid, &idxs)); 1353 PetscCall(ISGetLocalSize(gid, &cum)); 1354 PetscCall(PetscMalloc1(cum, &idxs2)); 1355 for (c = cStart, cum = 0; c < cEnd; c++) { 1356 if (idxs[c - cStart] < 0) continue; 1357 idxs2[cum++] = idxs[c - cStart]; 1358 } 1359 PetscCall(ISRestoreIndices(gid, &idxs)); 1360 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1361 PetscCall(ISDestroy(&gid)); 1362 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1363 1364 /* support for node-aware cell locality */ 1365 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1366 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1367 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1368 PetscCall(VecGetArray(cown, &array)); 1369 for (c = 0; c < numVertices; c++) array[c] = nid; 1370 PetscCall(VecRestoreArray(cown, &array)); 1371 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1372 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1373 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1374 PetscCall(ISDestroy(&acis)); 1375 PetscCall(VecScatterDestroy(&sct)); 1376 PetscCall(VecDestroy(&cown)); 1377 1378 /* compute edgeCut */ 1379 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1380 PetscCall(PetscMalloc1(cum, &work)); 1381 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1382 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1383 PetscCall(ISDestroy(&gid)); 1384 PetscCall(VecGetArray(acown, &array)); 1385 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1386 PetscInt totl; 1387 1388 totl = start[c + 1] - start[c]; 1389 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1390 for (i = 0; i < totl; i++) { 1391 if (work[i] < 0) { 1392 ect += 1; 1393 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1394 } 1395 } 1396 } 1397 PetscCall(PetscFree(work)); 1398 PetscCall(VecRestoreArray(acown, &array)); 1399 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1400 lm[1] = -numVertices; 1401 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1403 lm[0] = ect; /* edgeCut */ 1404 lm[1] = ectn; /* node-aware edgeCut */ 1405 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1406 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1407 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1408 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1409 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1410 #else 1411 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1412 #endif 1413 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1414 PetscCall(PetscFree(start)); 1415 PetscCall(PetscFree(adjacency)); 1416 PetscCall(VecDestroy(&acown)); 1417 } else { 1418 const char *name; 1419 PetscInt *sizes, *hybsizes, *ghostsizes; 1420 PetscInt locDepth, depth, cellHeight, dim, d; 1421 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1422 PetscInt numLabels, l, maxSize = 17; 1423 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1424 MPI_Comm comm; 1425 PetscMPIInt size, rank; 1426 1427 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1428 PetscCallMPI(MPI_Comm_size(comm, &size)); 1429 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1430 PetscCall(DMGetDimension(dm, &dim)); 1431 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1432 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1433 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1434 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1435 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1436 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1437 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1438 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1439 gcNum = gcEnd - gcStart; 1440 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1441 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1442 for (d = 0; d <= depth; d++) { 1443 PetscInt Nc[2] = {0, 0}, ict; 1444 1445 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1446 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1447 ict = ct0; 1448 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1449 ct0 = (DMPolytopeType)ict; 1450 for (p = pStart; p < pEnd; ++p) { 1451 DMPolytopeType ct; 1452 1453 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1454 if (ct == ct0) ++Nc[0]; 1455 else ++Nc[1]; 1456 } 1457 if (size < maxSize) { 1458 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1459 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1460 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1461 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1462 for (p = 0; p < size; ++p) { 1463 if (rank == 0) { 1464 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1465 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1466 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1467 } 1468 } 1469 } else { 1470 PetscInt locMinMax[2]; 1471 1472 locMinMax[0] = Nc[0] + Nc[1]; 1473 locMinMax[1] = Nc[0] + Nc[1]; 1474 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1475 locMinMax[0] = Nc[1]; 1476 locMinMax[1] = Nc[1]; 1477 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1478 if (d == depth) { 1479 locMinMax[0] = gcNum; 1480 locMinMax[1] = gcNum; 1481 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1482 } 1483 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1484 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1485 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1486 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1487 } 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1489 } 1490 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1491 { 1492 const PetscReal *maxCell; 1493 const PetscReal *L; 1494 PetscBool localized; 1495 1496 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1497 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1498 if (L || localized) { 1499 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1500 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1501 if (L) { 1502 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1503 for (d = 0; d < dim; ++d) { 1504 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1505 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1506 } 1507 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1508 } 1509 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1510 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1511 } 1512 } 1513 PetscCall(DMGetNumLabels(dm, &numLabels)); 1514 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1515 for (l = 0; l < numLabels; ++l) { 1516 DMLabel label; 1517 const char *name; 1518 IS valueIS; 1519 const PetscInt *values; 1520 PetscInt numValues, v; 1521 1522 PetscCall(DMGetLabelName(dm, l, &name)); 1523 PetscCall(DMGetLabel(dm, name, &label)); 1524 PetscCall(DMLabelGetNumValues(label, &numValues)); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1526 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1527 PetscCall(ISGetIndices(valueIS, &values)); 1528 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1529 for (v = 0; v < numValues; ++v) { 1530 PetscInt size; 1531 1532 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1533 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1534 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1535 } 1536 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1537 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1538 PetscCall(ISRestoreIndices(valueIS, &values)); 1539 PetscCall(ISDestroy(&valueIS)); 1540 } 1541 { 1542 char **labelNames; 1543 PetscInt Nl = numLabels; 1544 PetscBool flg; 1545 1546 PetscCall(PetscMalloc1(Nl, &labelNames)); 1547 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1548 for (l = 0; l < Nl; ++l) { 1549 DMLabel label; 1550 1551 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1552 if (flg) { 1553 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1554 PetscCall(DMLabelView(label, viewer)); 1555 } 1556 PetscCall(PetscFree(labelNames[l])); 1557 } 1558 PetscCall(PetscFree(labelNames)); 1559 } 1560 /* If no fields are specified, people do not want to see adjacency */ 1561 if (dm->Nf) { 1562 PetscInt f; 1563 1564 for (f = 0; f < dm->Nf; ++f) { 1565 const char *name; 1566 1567 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1568 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1569 PetscCall(PetscViewerASCIIPushTab(viewer)); 1570 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1571 if (dm->fields[f].adjacency[0]) { 1572 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1573 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1574 } else { 1575 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1576 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1577 } 1578 PetscCall(PetscViewerASCIIPopTab(viewer)); 1579 } 1580 } 1581 PetscCall(DMGetCoarseDM(dm, &cdm)); 1582 if (cdm) { 1583 PetscCall(PetscViewerASCIIPushTab(viewer)); 1584 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1585 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1586 PetscCall(PetscViewerASCIIPopTab(viewer)); 1587 } 1588 } 1589 PetscFunctionReturn(0); 1590 } 1591 1592 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1593 { 1594 DMPolytopeType ct; 1595 PetscMPIInt rank; 1596 PetscInt cdim; 1597 1598 PetscFunctionBegin; 1599 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1600 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1601 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1602 switch (ct) { 1603 case DM_POLYTOPE_SEGMENT: 1604 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1605 switch (cdim) { 1606 case 1: { 1607 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1608 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1609 1610 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1611 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1612 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1613 } break; 1614 case 2: { 1615 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1616 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1617 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1618 1619 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1620 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1621 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1622 } break; 1623 default: 1624 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1625 } 1626 break; 1627 case DM_POLYTOPE_TRIANGLE: 1628 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1629 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1630 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1631 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1632 break; 1633 case DM_POLYTOPE_QUADRILATERAL: 1634 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1635 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1636 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1637 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1638 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1639 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1640 break; 1641 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1642 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1643 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1644 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1645 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1646 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1647 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1648 break; 1649 case DM_POLYTOPE_FV_GHOST: 1650 break; 1651 default: 1652 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1653 } 1654 PetscFunctionReturn(0); 1655 } 1656 1657 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1658 { 1659 DMPolytopeType ct; 1660 PetscReal centroid[2] = {0., 0.}; 1661 PetscMPIInt rank; 1662 PetscInt fillColor, v, e, d; 1663 1664 PetscFunctionBegin; 1665 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1666 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1667 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1668 switch (ct) { 1669 case DM_POLYTOPE_TRIANGLE: { 1670 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1671 1672 for (v = 0; v < 3; ++v) { 1673 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1674 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1675 } 1676 for (e = 0; e < 3; ++e) { 1677 refCoords[0] = refVertices[e * 2 + 0]; 1678 refCoords[1] = refVertices[e * 2 + 1]; 1679 for (d = 1; d <= edgeDiv; ++d) { 1680 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1681 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1682 } 1683 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1684 for (d = 0; d < edgeDiv; ++d) { 1685 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1686 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1687 } 1688 } 1689 } break; 1690 default: 1691 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1692 } 1693 PetscFunctionReturn(0); 1694 } 1695 1696 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1697 { 1698 PetscDraw draw; 1699 DM cdm; 1700 PetscSection coordSection; 1701 Vec coordinates; 1702 const PetscScalar *coords; 1703 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1704 PetscReal *refCoords, *edgeCoords; 1705 PetscBool isnull, drawAffine = PETSC_TRUE; 1706 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1707 1708 PetscFunctionBegin; 1709 PetscCall(DMGetCoordinateDim(dm, &dim)); 1710 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1711 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1712 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1713 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1714 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1715 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1716 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1717 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1718 1719 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1720 PetscCall(PetscDrawIsNull(draw, &isnull)); 1721 if (isnull) PetscFunctionReturn(0); 1722 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1723 1724 PetscCall(VecGetLocalSize(coordinates, &N)); 1725 PetscCall(VecGetArrayRead(coordinates, &coords)); 1726 for (c = 0; c < N; c += dim) { 1727 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1728 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1729 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1730 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1731 } 1732 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1733 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1734 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1735 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1736 PetscCall(PetscDrawClear(draw)); 1737 1738 for (c = cStart; c < cEnd; ++c) { 1739 PetscScalar *coords = NULL; 1740 PetscInt numCoords; 1741 1742 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1743 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1744 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1745 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1746 } 1747 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1748 PetscCall(PetscDrawFlush(draw)); 1749 PetscCall(PetscDrawPause(draw)); 1750 PetscCall(PetscDrawSave(draw)); 1751 PetscFunctionReturn(0); 1752 } 1753 1754 #if defined(PETSC_HAVE_EXODUSII) 1755 #include <exodusII.h> 1756 #include <petscviewerexodusii.h> 1757 #endif 1758 1759 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1760 { 1761 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1762 char name[PETSC_MAX_PATH_LEN]; 1763 1764 PetscFunctionBegin; 1765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1766 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1768 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1769 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1770 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1771 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1773 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1774 if (iascii) { 1775 PetscViewerFormat format; 1776 PetscCall(PetscViewerGetFormat(viewer, &format)); 1777 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1778 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1779 } else if (ishdf5) { 1780 #if defined(PETSC_HAVE_HDF5) 1781 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1782 #else 1783 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1784 #endif 1785 } else if (isvtk) { 1786 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1787 } else if (isdraw) { 1788 PetscCall(DMPlexView_Draw(dm, viewer)); 1789 } else if (isglvis) { 1790 PetscCall(DMPlexView_GLVis(dm, viewer)); 1791 #if defined(PETSC_HAVE_EXODUSII) 1792 } else if (isexodus) { 1793 /* 1794 exodusII requires that all sets be part of exactly one cell set. 1795 If the dm does not have a "Cell Sets" label defined, we create one 1796 with ID 1, containig all cells. 1797 Note that if the Cell Sets label is defined but does not cover all cells, 1798 we may still have a problem. This should probably be checked here or in the viewer; 1799 */ 1800 PetscInt numCS; 1801 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1802 if (!numCS) { 1803 PetscInt cStart, cEnd, c; 1804 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1805 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1806 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1807 } 1808 PetscCall(DMView_PlexExodusII(dm, viewer)); 1809 #endif 1810 #if defined(PETSC_HAVE_CGNS) 1811 } else if (iscgns) { 1812 PetscCall(DMView_PlexCGNS(dm, viewer)); 1813 #endif 1814 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1815 /* Optionally view the partition */ 1816 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1817 if (flg) { 1818 Vec ranks; 1819 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1820 PetscCall(VecView(ranks, viewer)); 1821 PetscCall(VecDestroy(&ranks)); 1822 } 1823 /* Optionally view a label */ 1824 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1825 if (flg) { 1826 DMLabel label; 1827 Vec val; 1828 1829 PetscCall(DMGetLabel(dm, name, &label)); 1830 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1831 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1832 PetscCall(VecView(val, viewer)); 1833 PetscCall(VecDestroy(&val)); 1834 } 1835 PetscFunctionReturn(0); 1836 } 1837 1838 /*@ 1839 DMPlexTopologyView - Saves a DMPlex topology into a file 1840 1841 Collective on DM 1842 1843 Input Parameters: 1844 + dm - The DM whose topology is to be saved 1845 - viewer - The PetscViewer for saving 1846 1847 Level: advanced 1848 1849 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1850 @*/ 1851 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1852 { 1853 PetscBool ishdf5; 1854 1855 PetscFunctionBegin; 1856 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1857 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1858 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1859 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1860 if (ishdf5) { 1861 #if defined(PETSC_HAVE_HDF5) 1862 PetscViewerFormat format; 1863 PetscCall(PetscViewerGetFormat(viewer, &format)); 1864 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1865 IS globalPointNumbering; 1866 1867 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1868 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1869 PetscCall(ISDestroy(&globalPointNumbering)); 1870 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1871 #else 1872 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1873 #endif 1874 } 1875 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1876 PetscFunctionReturn(0); 1877 } 1878 1879 /*@ 1880 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1881 1882 Collective on DM 1883 1884 Input Parameters: 1885 + dm - The DM whose coordinates are to be saved 1886 - viewer - The PetscViewer for saving 1887 1888 Level: advanced 1889 1890 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1891 @*/ 1892 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1893 { 1894 PetscBool ishdf5; 1895 1896 PetscFunctionBegin; 1897 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1898 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1899 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1900 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1901 if (ishdf5) { 1902 #if defined(PETSC_HAVE_HDF5) 1903 PetscViewerFormat format; 1904 PetscCall(PetscViewerGetFormat(viewer, &format)); 1905 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1906 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1907 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1908 #else 1909 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1910 #endif 1911 } 1912 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1913 PetscFunctionReturn(0); 1914 } 1915 1916 /*@ 1917 DMPlexLabelsView - Saves DMPlex labels into a file 1918 1919 Collective on DM 1920 1921 Input Parameters: 1922 + dm - The DM whose labels are to be saved 1923 - viewer - The PetscViewer for saving 1924 1925 Level: advanced 1926 1927 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1928 @*/ 1929 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1930 { 1931 PetscBool ishdf5; 1932 1933 PetscFunctionBegin; 1934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1935 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1936 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1937 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1938 if (ishdf5) { 1939 #if defined(PETSC_HAVE_HDF5) 1940 IS globalPointNumbering; 1941 PetscViewerFormat format; 1942 1943 PetscCall(PetscViewerGetFormat(viewer, &format)); 1944 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1945 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1946 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1947 PetscCall(ISDestroy(&globalPointNumbering)); 1948 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1949 #else 1950 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1951 #endif 1952 } 1953 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1954 PetscFunctionReturn(0); 1955 } 1956 1957 /*@ 1958 DMPlexSectionView - Saves a section associated with a DMPlex 1959 1960 Collective on DM 1961 1962 Input Parameters: 1963 + dm - The DM that contains the topology on which the section to be saved is defined 1964 . viewer - The PetscViewer for saving 1965 - sectiondm - The DM that contains the section to be saved 1966 1967 Level: advanced 1968 1969 Notes: 1970 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1971 1972 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1973 1974 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1975 @*/ 1976 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1977 { 1978 PetscBool ishdf5; 1979 1980 PetscFunctionBegin; 1981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1982 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1983 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1984 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1985 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1986 if (ishdf5) { 1987 #if defined(PETSC_HAVE_HDF5) 1988 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1989 #else 1990 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1991 #endif 1992 } 1993 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1994 PetscFunctionReturn(0); 1995 } 1996 1997 /*@ 1998 DMPlexGlobalVectorView - Saves a global vector 1999 2000 Collective on DM 2001 2002 Input Parameters: 2003 + dm - The DM that represents the topology 2004 . viewer - The PetscViewer to save data with 2005 . sectiondm - The DM that contains the global section on which vec is defined 2006 - vec - The global vector to be saved 2007 2008 Level: advanced 2009 2010 Notes: 2011 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2012 2013 Typical calling sequence 2014 $ DMCreate(PETSC_COMM_WORLD, &dm); 2015 $ DMSetType(dm, DMPLEX); 2016 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2017 $ DMClone(dm, §iondm); 2018 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2019 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2020 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2021 $ PetscSectionSetChart(section, pStart, pEnd); 2022 $ PetscSectionSetUp(section); 2023 $ DMSetLocalSection(sectiondm, section); 2024 $ PetscSectionDestroy(§ion); 2025 $ DMGetGlobalVector(sectiondm, &vec); 2026 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2027 $ DMPlexTopologyView(dm, viewer); 2028 $ DMPlexSectionView(dm, viewer, sectiondm); 2029 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2030 $ DMRestoreGlobalVector(sectiondm, &vec); 2031 $ DMDestroy(§iondm); 2032 $ DMDestroy(&dm); 2033 2034 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2035 @*/ 2036 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2037 { 2038 PetscBool ishdf5; 2039 2040 PetscFunctionBegin; 2041 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2042 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2043 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2044 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2045 /* Check consistency */ 2046 { 2047 PetscSection section; 2048 PetscBool includesConstraints; 2049 PetscInt m, m1; 2050 2051 PetscCall(VecGetLocalSize(vec, &m1)); 2052 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2053 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2054 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2055 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2056 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2057 } 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2059 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2060 if (ishdf5) { 2061 #if defined(PETSC_HAVE_HDF5) 2062 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2063 #else 2064 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2065 #endif 2066 } 2067 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2068 PetscFunctionReturn(0); 2069 } 2070 2071 /*@ 2072 DMPlexLocalVectorView - Saves a local vector 2073 2074 Collective on DM 2075 2076 Input Parameters: 2077 + dm - The DM that represents the topology 2078 . viewer - The PetscViewer to save data with 2079 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2080 - vec - The local vector to be saved 2081 2082 Level: advanced 2083 2084 Notes: 2085 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2086 2087 Typical calling sequence 2088 $ DMCreate(PETSC_COMM_WORLD, &dm); 2089 $ DMSetType(dm, DMPLEX); 2090 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2091 $ DMClone(dm, §iondm); 2092 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2093 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2094 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2095 $ PetscSectionSetChart(section, pStart, pEnd); 2096 $ PetscSectionSetUp(section); 2097 $ DMSetLocalSection(sectiondm, section); 2098 $ DMGetLocalVector(sectiondm, &vec); 2099 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2100 $ DMPlexTopologyView(dm, viewer); 2101 $ DMPlexSectionView(dm, viewer, sectiondm); 2102 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2103 $ DMRestoreLocalVector(sectiondm, &vec); 2104 $ DMDestroy(§iondm); 2105 $ DMDestroy(&dm); 2106 2107 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2108 @*/ 2109 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2110 { 2111 PetscBool ishdf5; 2112 2113 PetscFunctionBegin; 2114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2115 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2116 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2117 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2118 /* Check consistency */ 2119 { 2120 PetscSection section; 2121 PetscBool includesConstraints; 2122 PetscInt m, m1; 2123 2124 PetscCall(VecGetLocalSize(vec, &m1)); 2125 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2126 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2127 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2128 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2129 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2130 } 2131 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2132 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2133 if (ishdf5) { 2134 #if defined(PETSC_HAVE_HDF5) 2135 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2136 #else 2137 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2138 #endif 2139 } 2140 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2141 PetscFunctionReturn(0); 2142 } 2143 2144 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2145 { 2146 PetscBool ishdf5; 2147 2148 PetscFunctionBegin; 2149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2150 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2151 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2152 if (ishdf5) { 2153 #if defined(PETSC_HAVE_HDF5) 2154 PetscViewerFormat format; 2155 PetscCall(PetscViewerGetFormat(viewer, &format)); 2156 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2157 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2158 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2159 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2160 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2161 PetscFunctionReturn(0); 2162 #else 2163 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2164 #endif 2165 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2166 } 2167 2168 /*@ 2169 DMPlexTopologyLoad - Loads a topology into a DMPlex 2170 2171 Collective on DM 2172 2173 Input Parameters: 2174 + dm - The DM into which the topology is loaded 2175 - viewer - The PetscViewer for the saved topology 2176 2177 Output Parameters: 2178 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2179 2180 Level: advanced 2181 2182 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2183 @*/ 2184 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2185 { 2186 PetscBool ishdf5; 2187 2188 PetscFunctionBegin; 2189 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2190 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2191 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2192 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2193 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2194 if (ishdf5) { 2195 #if defined(PETSC_HAVE_HDF5) 2196 PetscViewerFormat format; 2197 PetscCall(PetscViewerGetFormat(viewer, &format)); 2198 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2199 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2200 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2201 #else 2202 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2203 #endif 2204 } 2205 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2206 PetscFunctionReturn(0); 2207 } 2208 2209 /*@ 2210 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2211 2212 Collective on DM 2213 2214 Input Parameters: 2215 + dm - The DM into which the coordinates are loaded 2216 . viewer - The PetscViewer for the saved coordinates 2217 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2218 2219 Level: advanced 2220 2221 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2222 @*/ 2223 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2224 { 2225 PetscBool ishdf5; 2226 2227 PetscFunctionBegin; 2228 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2229 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2230 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2231 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2232 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2233 if (ishdf5) { 2234 #if defined(PETSC_HAVE_HDF5) 2235 PetscViewerFormat format; 2236 PetscCall(PetscViewerGetFormat(viewer, &format)); 2237 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2238 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2239 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2240 #else 2241 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2242 #endif 2243 } 2244 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2245 PetscFunctionReturn(0); 2246 } 2247 2248 /*@ 2249 DMPlexLabelsLoad - Loads labels into a DMPlex 2250 2251 Collective on DM 2252 2253 Input Parameters: 2254 + dm - The DM into which the labels are loaded 2255 . viewer - The PetscViewer for the saved labels 2256 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2257 2258 Level: advanced 2259 2260 Notes: 2261 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2262 2263 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2264 @*/ 2265 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2266 { 2267 PetscBool ishdf5; 2268 2269 PetscFunctionBegin; 2270 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2271 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2272 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2273 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2274 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2275 if (ishdf5) { 2276 #if defined(PETSC_HAVE_HDF5) 2277 PetscViewerFormat format; 2278 2279 PetscCall(PetscViewerGetFormat(viewer, &format)); 2280 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2281 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2282 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2283 #else 2284 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2285 #endif 2286 } 2287 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2288 PetscFunctionReturn(0); 2289 } 2290 2291 /*@ 2292 DMPlexSectionLoad - Loads section into a DMPlex 2293 2294 Collective on DM 2295 2296 Input Parameters: 2297 + dm - The DM that represents the topology 2298 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2299 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2300 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2301 2302 Output Parameters 2303 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2304 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2305 2306 Level: advanced 2307 2308 Notes: 2309 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2310 2311 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2312 2313 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2314 2315 Example using 2 processes: 2316 $ NX (number of points on dm): 4 2317 $ sectionA : the on-disk section 2318 $ vecA : a vector associated with sectionA 2319 $ sectionB : sectiondm's local section constructed in this function 2320 $ vecB (local) : a vector associated with sectiondm's local section 2321 $ vecB (global) : a vector associated with sectiondm's global section 2322 $ 2323 $ rank 0 rank 1 2324 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2325 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2326 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2327 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2328 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2329 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2330 $ sectionB->atlasDof : 1 0 1 | 1 3 2331 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2332 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2333 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2334 $ 2335 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2336 2337 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2338 @*/ 2339 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2340 { 2341 PetscBool ishdf5; 2342 2343 PetscFunctionBegin; 2344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2345 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2346 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2347 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2348 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2349 if (localDofSF) PetscValidPointer(localDofSF, 6); 2350 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2351 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2352 if (ishdf5) { 2353 #if defined(PETSC_HAVE_HDF5) 2354 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2355 #else 2356 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2357 #endif 2358 } 2359 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2360 PetscFunctionReturn(0); 2361 } 2362 2363 /*@ 2364 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2365 2366 Collective on DM 2367 2368 Input Parameters: 2369 + dm - The DM that represents the topology 2370 . viewer - The PetscViewer that represents the on-disk vector data 2371 . sectiondm - The DM that contains the global section on which vec is defined 2372 . sf - The SF that migrates the on-disk vector data into vec 2373 - vec - The global vector to set values of 2374 2375 Level: advanced 2376 2377 Notes: 2378 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2379 2380 Typical calling sequence 2381 $ DMCreate(PETSC_COMM_WORLD, &dm); 2382 $ DMSetType(dm, DMPLEX); 2383 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2384 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2385 $ DMClone(dm, §iondm); 2386 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2387 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2388 $ DMGetGlobalVector(sectiondm, &vec); 2389 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2390 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2391 $ DMRestoreGlobalVector(sectiondm, &vec); 2392 $ PetscSFDestroy(&gsf); 2393 $ PetscSFDestroy(&sfX); 2394 $ DMDestroy(§iondm); 2395 $ DMDestroy(&dm); 2396 2397 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2398 @*/ 2399 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2400 { 2401 PetscBool ishdf5; 2402 2403 PetscFunctionBegin; 2404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2405 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2406 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2407 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2408 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2409 /* Check consistency */ 2410 { 2411 PetscSection section; 2412 PetscBool includesConstraints; 2413 PetscInt m, m1; 2414 2415 PetscCall(VecGetLocalSize(vec, &m1)); 2416 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2417 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2418 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2419 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2420 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2421 } 2422 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2423 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2424 if (ishdf5) { 2425 #if defined(PETSC_HAVE_HDF5) 2426 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2427 #else 2428 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2429 #endif 2430 } 2431 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2432 PetscFunctionReturn(0); 2433 } 2434 2435 /*@ 2436 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2437 2438 Collective on DM 2439 2440 Input Parameters: 2441 + dm - The DM that represents the topology 2442 . viewer - The PetscViewer that represents the on-disk vector data 2443 . sectiondm - The DM that contains the local section on which vec is defined 2444 . sf - The SF that migrates the on-disk vector data into vec 2445 - vec - The local vector to set values of 2446 2447 Level: advanced 2448 2449 Notes: 2450 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2451 2452 Typical calling sequence 2453 $ DMCreate(PETSC_COMM_WORLD, &dm); 2454 $ DMSetType(dm, DMPLEX); 2455 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2456 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2457 $ DMClone(dm, §iondm); 2458 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2459 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2460 $ DMGetLocalVector(sectiondm, &vec); 2461 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2462 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2463 $ DMRestoreLocalVector(sectiondm, &vec); 2464 $ PetscSFDestroy(&lsf); 2465 $ PetscSFDestroy(&sfX); 2466 $ DMDestroy(§iondm); 2467 $ DMDestroy(&dm); 2468 2469 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2470 @*/ 2471 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2472 { 2473 PetscBool ishdf5; 2474 2475 PetscFunctionBegin; 2476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2477 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2478 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2479 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2480 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2481 /* Check consistency */ 2482 { 2483 PetscSection section; 2484 PetscBool includesConstraints; 2485 PetscInt m, m1; 2486 2487 PetscCall(VecGetLocalSize(vec, &m1)); 2488 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2489 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2490 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2491 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2492 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2493 } 2494 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2495 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2496 if (ishdf5) { 2497 #if defined(PETSC_HAVE_HDF5) 2498 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2499 #else 2500 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2501 #endif 2502 } 2503 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2504 PetscFunctionReturn(0); 2505 } 2506 2507 PetscErrorCode DMDestroy_Plex(DM dm) 2508 { 2509 DM_Plex *mesh = (DM_Plex *)dm->data; 2510 2511 PetscFunctionBegin; 2512 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2513 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2514 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2515 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2516 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2517 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2518 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2519 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2520 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2521 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2522 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2523 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2524 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2525 if (--mesh->refct > 0) PetscFunctionReturn(0); 2526 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2527 PetscCall(PetscFree(mesh->cones)); 2528 PetscCall(PetscFree(mesh->coneOrientations)); 2529 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2530 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2531 PetscCall(PetscFree(mesh->supports)); 2532 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2533 PetscCall(PetscFree(mesh->facesTmp)); 2534 PetscCall(PetscFree(mesh->tetgenOpts)); 2535 PetscCall(PetscFree(mesh->triangleOpts)); 2536 PetscCall(PetscFree(mesh->transformType)); 2537 PetscCall(PetscFree(mesh->distributionName)); 2538 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2539 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2540 PetscCall(ISDestroy(&mesh->subpointIS)); 2541 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2542 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2543 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2544 PetscCall(ISDestroy(&mesh->anchorIS)); 2545 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2546 PetscCall(PetscFree(mesh->parents)); 2547 PetscCall(PetscFree(mesh->childIDs)); 2548 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2549 PetscCall(PetscFree(mesh->children)); 2550 PetscCall(DMDestroy(&mesh->referenceTree)); 2551 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2552 PetscCall(PetscFree(mesh->neighbors)); 2553 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2554 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2555 PetscCall(PetscFree(mesh)); 2556 PetscFunctionReturn(0); 2557 } 2558 2559 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2560 { 2561 PetscSection sectionGlobal; 2562 PetscInt bs = -1, mbs; 2563 PetscInt localSize, localStart = 0; 2564 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2565 MatType mtype; 2566 ISLocalToGlobalMapping ltog; 2567 2568 PetscFunctionBegin; 2569 PetscCall(MatInitializePackage()); 2570 mtype = dm->mattype; 2571 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2572 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2573 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2574 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2575 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2576 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2577 PetscCall(MatSetType(*J, mtype)); 2578 PetscCall(MatSetFromOptions(*J)); 2579 PetscCall(MatGetBlockSize(*J, &mbs)); 2580 if (mbs > 1) bs = mbs; 2581 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2582 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2583 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2584 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2585 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2586 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2587 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2588 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2589 if (!isShell) { 2590 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2591 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2592 PetscInt pStart, pEnd, p, dof, cdof; 2593 2594 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2595 2596 PetscCall(PetscCalloc1(localSize, &pblocks)); 2597 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2598 for (p = pStart; p < pEnd; ++p) { 2599 PetscInt bdof, offset; 2600 2601 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2602 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2603 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2604 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2605 dof = dof < 0 ? -(dof + 1) : dof; 2606 bdof = cdof && (dof - cdof) ? 1 : dof; 2607 if (dof) { 2608 if (bs < 0) { 2609 bs = bdof; 2610 } else if (bs != bdof) { 2611 bs = 1; 2612 } 2613 } 2614 } 2615 /* Must have same blocksize on all procs (some might have no points) */ 2616 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2617 bsLocal[1] = bs; 2618 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2619 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2620 else bs = bsMinMax[0]; 2621 bs = PetscMax(1, bs); 2622 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2623 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2624 PetscCall(MatSetBlockSize(*J, bs)); 2625 PetscCall(MatSetUp(*J)); 2626 } else { 2627 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2628 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2629 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2630 } 2631 { // Consolidate blocks 2632 PetscInt nblocks = 0; 2633 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2634 if (pblocks[i] == 0) continue; 2635 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2636 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2637 } 2638 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2639 } 2640 PetscCall(PetscFree(pblocks)); 2641 } 2642 PetscCall(MatSetDM(*J, dm)); 2643 PetscFunctionReturn(0); 2644 } 2645 2646 /*@ 2647 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2648 2649 Not collective 2650 2651 Input Parameter: 2652 . mesh - The DMPlex 2653 2654 Output Parameters: 2655 . subsection - The subdomain section 2656 2657 Level: developer 2658 2659 .seealso: 2660 @*/ 2661 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2662 { 2663 DM_Plex *mesh = (DM_Plex *)dm->data; 2664 2665 PetscFunctionBegin; 2666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2667 if (!mesh->subdomainSection) { 2668 PetscSection section; 2669 PetscSF sf; 2670 2671 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2672 PetscCall(DMGetLocalSection(dm, §ion)); 2673 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2674 PetscCall(PetscSFDestroy(&sf)); 2675 } 2676 *subsection = mesh->subdomainSection; 2677 PetscFunctionReturn(0); 2678 } 2679 2680 /*@ 2681 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2682 2683 Not collective 2684 2685 Input Parameter: 2686 . mesh - The DMPlex 2687 2688 Output Parameters: 2689 + pStart - The first mesh point 2690 - pEnd - The upper bound for mesh points 2691 2692 Level: beginner 2693 2694 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2695 @*/ 2696 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2697 { 2698 DM_Plex *mesh = (DM_Plex *)dm->data; 2699 2700 PetscFunctionBegin; 2701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2702 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2703 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2704 PetscFunctionReturn(0); 2705 } 2706 2707 /*@ 2708 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2709 2710 Not collective 2711 2712 Input Parameters: 2713 + mesh - The DMPlex 2714 . pStart - The first mesh point 2715 - pEnd - The upper bound for mesh points 2716 2717 Output Parameters: 2718 2719 Level: beginner 2720 2721 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2722 @*/ 2723 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2724 { 2725 DM_Plex *mesh = (DM_Plex *)dm->data; 2726 2727 PetscFunctionBegin; 2728 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2729 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2730 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2731 PetscFunctionReturn(0); 2732 } 2733 2734 /*@ 2735 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2736 2737 Not collective 2738 2739 Input Parameters: 2740 + mesh - The DMPlex 2741 - p - The point, which must lie in the chart set with DMPlexSetChart() 2742 2743 Output Parameter: 2744 . size - The cone size for point p 2745 2746 Level: beginner 2747 2748 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2749 @*/ 2750 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2751 { 2752 DM_Plex *mesh = (DM_Plex *)dm->data; 2753 2754 PetscFunctionBegin; 2755 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2756 PetscValidIntPointer(size, 3); 2757 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2758 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2759 PetscFunctionReturn(0); 2760 } 2761 2762 /*@ 2763 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2764 2765 Not collective 2766 2767 Input Parameters: 2768 + mesh - The DMPlex 2769 . p - The point, which must lie in the chart set with DMPlexSetChart() 2770 - size - The cone size for point p 2771 2772 Output Parameter: 2773 2774 Note: 2775 This should be called after DMPlexSetChart(). 2776 2777 Level: beginner 2778 2779 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2780 @*/ 2781 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2782 { 2783 DM_Plex *mesh = (DM_Plex *)dm->data; 2784 2785 PetscFunctionBegin; 2786 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2787 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2788 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2789 PetscFunctionReturn(0); 2790 } 2791 2792 /*@C 2793 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2794 2795 Not collective 2796 2797 Input Parameters: 2798 + dm - The DMPlex 2799 - p - The point, which must lie in the chart set with DMPlexSetChart() 2800 2801 Output Parameter: 2802 . cone - An array of points which are on the in-edges for point p 2803 2804 Level: beginner 2805 2806 Fortran Notes: 2807 Since it returns an array, this routine is only available in Fortran 90, and you must 2808 include petsc.h90 in your code. 2809 You must also call DMPlexRestoreCone() after you finish using the returned array. 2810 DMPlexRestoreCone() is not needed/available in C. 2811 2812 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2813 @*/ 2814 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2815 { 2816 DM_Plex *mesh = (DM_Plex *)dm->data; 2817 PetscInt off; 2818 2819 PetscFunctionBegin; 2820 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2821 PetscValidPointer(cone, 3); 2822 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2823 *cone = &mesh->cones[off]; 2824 PetscFunctionReturn(0); 2825 } 2826 2827 /*@C 2828 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2829 2830 Not collective 2831 2832 Input Parameters: 2833 + dm - The DMPlex 2834 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2835 2836 Output Parameters: 2837 + pConesSection - PetscSection describing the layout of pCones 2838 - pCones - An array of points which are on the in-edges for the point set p 2839 2840 Level: intermediate 2841 2842 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2843 @*/ 2844 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2845 { 2846 PetscSection cs, newcs; 2847 PetscInt *cones; 2848 PetscInt *newarr = NULL; 2849 PetscInt n; 2850 2851 PetscFunctionBegin; 2852 PetscCall(DMPlexGetCones(dm, &cones)); 2853 PetscCall(DMPlexGetConeSection(dm, &cs)); 2854 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2855 if (pConesSection) *pConesSection = newcs; 2856 if (pCones) { 2857 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2858 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2859 } 2860 PetscFunctionReturn(0); 2861 } 2862 2863 /*@ 2864 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2865 2866 Not collective 2867 2868 Input Parameters: 2869 + dm - The DMPlex 2870 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2871 2872 Output Parameter: 2873 . expandedPoints - An array of vertices recursively expanded from input points 2874 2875 Level: advanced 2876 2877 Notes: 2878 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2879 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2880 2881 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2882 @*/ 2883 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2884 { 2885 IS *expandedPointsAll; 2886 PetscInt depth; 2887 2888 PetscFunctionBegin; 2889 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2890 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2891 PetscValidPointer(expandedPoints, 3); 2892 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2893 *expandedPoints = expandedPointsAll[0]; 2894 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2895 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2896 PetscFunctionReturn(0); 2897 } 2898 2899 /*@ 2900 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). 2901 2902 Not collective 2903 2904 Input Parameters: 2905 + dm - The DMPlex 2906 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2907 2908 Output Parameters: 2909 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2910 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2911 - sections - (optional) An array of sections which describe mappings from points to their cone points 2912 2913 Level: advanced 2914 2915 Notes: 2916 Like DMPlexGetConeTuple() but recursive. 2917 2918 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. 2919 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2920 2921 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: 2922 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2923 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2924 2925 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2926 @*/ 2927 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2928 { 2929 const PetscInt *arr0 = NULL, *cone = NULL; 2930 PetscInt *arr = NULL, *newarr = NULL; 2931 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2932 IS *expandedPoints_; 2933 PetscSection *sections_; 2934 2935 PetscFunctionBegin; 2936 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2937 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2938 if (depth) PetscValidIntPointer(depth, 3); 2939 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2940 if (sections) PetscValidPointer(sections, 5); 2941 PetscCall(ISGetLocalSize(points, &n)); 2942 PetscCall(ISGetIndices(points, &arr0)); 2943 PetscCall(DMPlexGetDepth(dm, &depth_)); 2944 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2945 PetscCall(PetscCalloc1(depth_, §ions_)); 2946 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2947 for (d = depth_ - 1; d >= 0; d--) { 2948 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2949 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2950 for (i = 0; i < n; i++) { 2951 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2952 if (arr[i] >= start && arr[i] < end) { 2953 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2954 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2955 } else { 2956 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2957 } 2958 } 2959 PetscCall(PetscSectionSetUp(sections_[d])); 2960 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2961 PetscCall(PetscMalloc1(newn, &newarr)); 2962 for (i = 0; i < n; i++) { 2963 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2964 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2965 if (cn > 1) { 2966 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2967 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2968 } else { 2969 newarr[co] = arr[i]; 2970 } 2971 } 2972 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2973 arr = newarr; 2974 n = newn; 2975 } 2976 PetscCall(ISRestoreIndices(points, &arr0)); 2977 *depth = depth_; 2978 if (expandedPoints) *expandedPoints = expandedPoints_; 2979 else { 2980 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2981 PetscCall(PetscFree(expandedPoints_)); 2982 } 2983 if (sections) *sections = sections_; 2984 else { 2985 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2986 PetscCall(PetscFree(sections_)); 2987 } 2988 PetscFunctionReturn(0); 2989 } 2990 2991 /*@ 2992 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2993 2994 Not collective 2995 2996 Input Parameters: 2997 + dm - The DMPlex 2998 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2999 3000 Output Parameters: 3001 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 3002 . expandedPoints - (optional) An array of recursively expanded cones 3003 - sections - (optional) An array of sections which describe mappings from points to their cone points 3004 3005 Level: advanced 3006 3007 Notes: 3008 See DMPlexGetConeRecursive() for details. 3009 3010 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 3011 @*/ 3012 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3013 { 3014 PetscInt d, depth_; 3015 3016 PetscFunctionBegin; 3017 PetscCall(DMPlexGetDepth(dm, &depth_)); 3018 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3019 if (depth) *depth = 0; 3020 if (expandedPoints) { 3021 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3022 PetscCall(PetscFree(*expandedPoints)); 3023 } 3024 if (sections) { 3025 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3026 PetscCall(PetscFree(*sections)); 3027 } 3028 PetscFunctionReturn(0); 3029 } 3030 3031 /*@ 3032 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 3033 3034 Not collective 3035 3036 Input Parameters: 3037 + mesh - The DMPlex 3038 . p - The point, which must lie in the chart set with DMPlexSetChart() 3039 - cone - An array of points which are on the in-edges for point p 3040 3041 Output Parameter: 3042 3043 Note: 3044 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3045 3046 Level: beginner 3047 3048 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3049 @*/ 3050 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3051 { 3052 DM_Plex *mesh = (DM_Plex *)dm->data; 3053 PetscInt pStart, pEnd; 3054 PetscInt dof, off, c; 3055 3056 PetscFunctionBegin; 3057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3058 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3059 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3060 if (dof) PetscValidIntPointer(cone, 3); 3061 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3062 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3063 for (c = 0; c < dof; ++c) { 3064 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3065 mesh->cones[off + c] = cone[c]; 3066 } 3067 PetscFunctionReturn(0); 3068 } 3069 3070 /*@C 3071 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3072 3073 Not collective 3074 3075 Input Parameters: 3076 + mesh - The DMPlex 3077 - p - The point, which must lie in the chart set with DMPlexSetChart() 3078 3079 Output Parameter: 3080 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3081 integer giving the prescription for cone traversal. 3082 3083 Level: beginner 3084 3085 Notes: 3086 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3087 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3088 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3089 with the identity. 3090 3091 Fortran Notes: 3092 Since it returns an array, this routine is only available in Fortran 90, and you must 3093 include petsc.h90 in your code. 3094 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3095 DMPlexRestoreConeOrientation() is not needed/available in C. 3096 3097 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3098 @*/ 3099 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3100 { 3101 DM_Plex *mesh = (DM_Plex *)dm->data; 3102 PetscInt off; 3103 3104 PetscFunctionBegin; 3105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3106 if (PetscDefined(USE_DEBUG)) { 3107 PetscInt dof; 3108 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3109 if (dof) PetscValidPointer(coneOrientation, 3); 3110 } 3111 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3112 3113 *coneOrientation = &mesh->coneOrientations[off]; 3114 PetscFunctionReturn(0); 3115 } 3116 3117 /*@ 3118 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3119 3120 Not collective 3121 3122 Input Parameters: 3123 + mesh - The DMPlex 3124 . p - The point, which must lie in the chart set with DMPlexSetChart() 3125 - coneOrientation - An array of orientations 3126 Output Parameter: 3127 3128 Notes: 3129 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3130 3131 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3132 3133 Level: beginner 3134 3135 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3136 @*/ 3137 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3138 { 3139 DM_Plex *mesh = (DM_Plex *)dm->data; 3140 PetscInt pStart, pEnd; 3141 PetscInt dof, off, c; 3142 3143 PetscFunctionBegin; 3144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3145 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3146 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3147 if (dof) PetscValidIntPointer(coneOrientation, 3); 3148 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3149 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3150 for (c = 0; c < dof; ++c) { 3151 PetscInt cdof, o = coneOrientation[c]; 3152 3153 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3154 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3155 mesh->coneOrientations[off + c] = o; 3156 } 3157 PetscFunctionReturn(0); 3158 } 3159 3160 /*@ 3161 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3162 3163 Not collective 3164 3165 Input Parameters: 3166 + mesh - The DMPlex 3167 . p - The point, which must lie in the chart set with DMPlexSetChart() 3168 . conePos - The local index in the cone where the point should be put 3169 - conePoint - The mesh point to insert 3170 3171 Level: beginner 3172 3173 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3174 @*/ 3175 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3176 { 3177 DM_Plex *mesh = (DM_Plex *)dm->data; 3178 PetscInt pStart, pEnd; 3179 PetscInt dof, off; 3180 3181 PetscFunctionBegin; 3182 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3183 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3184 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3185 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3186 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3187 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3188 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3189 mesh->cones[off + conePos] = conePoint; 3190 PetscFunctionReturn(0); 3191 } 3192 3193 /*@ 3194 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3195 3196 Not collective 3197 3198 Input Parameters: 3199 + mesh - The DMPlex 3200 . p - The point, which must lie in the chart set with DMPlexSetChart() 3201 . conePos - The local index in the cone where the point should be put 3202 - coneOrientation - The point orientation to insert 3203 3204 Level: beginner 3205 3206 Notes: 3207 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3208 3209 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3210 @*/ 3211 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3212 { 3213 DM_Plex *mesh = (DM_Plex *)dm->data; 3214 PetscInt pStart, pEnd; 3215 PetscInt dof, off; 3216 3217 PetscFunctionBegin; 3218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3219 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3220 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3221 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3222 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3223 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3224 mesh->coneOrientations[off + conePos] = coneOrientation; 3225 PetscFunctionReturn(0); 3226 } 3227 3228 /*@C 3229 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3230 3231 Not collective 3232 3233 Input Parameters: 3234 + dm - The DMPlex 3235 - p - The point, which must lie in the chart set with DMPlexSetChart() 3236 3237 Output Parameters: 3238 + cone - An array of points which are on the in-edges for point p 3239 - ornt - An array of orientations which are on the in-edges for point p. An orientation is an 3240 integer giving the prescription for cone traversal. 3241 3242 Level: beginner 3243 3244 Notes: 3245 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3246 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3247 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3248 with the identity. 3249 3250 Fortran Notes: 3251 Since it returns an array, this routine is only available in Fortran 90, and you must 3252 include petsc.h90 in your code. 3253 You must also call DMPlexRestoreCone() after you finish using the returned array. 3254 DMPlexRestoreCone() is not needed/available in C. 3255 3256 .seealso: `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3257 @*/ 3258 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3259 { 3260 DM_Plex *mesh = (DM_Plex *)dm->data; 3261 3262 PetscFunctionBegin; 3263 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3264 if (mesh->tr) { 3265 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3266 } else { 3267 PetscInt off; 3268 if (PetscDefined(USE_DEBUG)) { 3269 PetscInt dof; 3270 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3271 if (dof) { 3272 if (cone) PetscValidPointer(cone, 3); 3273 if (ornt) PetscValidPointer(ornt, 4); 3274 } 3275 } 3276 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3277 if (cone) *cone = &mesh->cones[off]; 3278 if (ornt) *ornt = &mesh->coneOrientations[off]; 3279 } 3280 PetscFunctionReturn(0); 3281 } 3282 3283 /*@C 3284 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3285 3286 Not collective 3287 3288 Input Parameters: 3289 + dm - The DMPlex 3290 . p - The point, which must lie in the chart set with DMPlexSetChart() 3291 . cone - An array of points which are on the in-edges for point p 3292 - ornt - An array of orientations which are on the in-edges for point p. An orientation is an 3293 integer giving the prescription for cone traversal. 3294 3295 Level: beginner 3296 3297 Notes: 3298 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3299 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3300 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3301 with the identity. 3302 3303 Fortran Notes: 3304 Since it returns an array, this routine is only available in Fortran 90, and you must 3305 include petsc.h90 in your code. 3306 You must also call DMPlexRestoreCone() after you finish using the returned array. 3307 DMPlexRestoreCone() is not needed/available in C. 3308 3309 .seealso: `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3310 @*/ 3311 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3312 { 3313 DM_Plex *mesh = (DM_Plex *)dm->data; 3314 3315 PetscFunctionBegin; 3316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3317 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3318 PetscFunctionReturn(0); 3319 } 3320 3321 /*@ 3322 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3323 3324 Not collective 3325 3326 Input Parameters: 3327 + mesh - The DMPlex 3328 - p - The point, which must lie in the chart set with DMPlexSetChart() 3329 3330 Output Parameter: 3331 . size - The support size for point p 3332 3333 Level: beginner 3334 3335 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3336 @*/ 3337 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3338 { 3339 DM_Plex *mesh = (DM_Plex *)dm->data; 3340 3341 PetscFunctionBegin; 3342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3343 PetscValidIntPointer(size, 3); 3344 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3345 PetscFunctionReturn(0); 3346 } 3347 3348 /*@ 3349 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3350 3351 Not collective 3352 3353 Input Parameters: 3354 + mesh - The DMPlex 3355 . p - The point, which must lie in the chart set with DMPlexSetChart() 3356 - size - The support size for point p 3357 3358 Output Parameter: 3359 3360 Note: 3361 This should be called after DMPlexSetChart(). 3362 3363 Level: beginner 3364 3365 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3366 @*/ 3367 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3368 { 3369 DM_Plex *mesh = (DM_Plex *)dm->data; 3370 3371 PetscFunctionBegin; 3372 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3373 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3374 PetscFunctionReturn(0); 3375 } 3376 3377 /*@C 3378 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3379 3380 Not collective 3381 3382 Input Parameters: 3383 + mesh - The DMPlex 3384 - p - The point, which must lie in the chart set with DMPlexSetChart() 3385 3386 Output Parameter: 3387 . support - An array of points which are on the out-edges for point p 3388 3389 Level: beginner 3390 3391 Fortran Notes: 3392 Since it returns an array, this routine is only available in Fortran 90, and you must 3393 include petsc.h90 in your code. 3394 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3395 DMPlexRestoreSupport() is not needed/available in C. 3396 3397 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3398 @*/ 3399 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3400 { 3401 DM_Plex *mesh = (DM_Plex *)dm->data; 3402 PetscInt off; 3403 3404 PetscFunctionBegin; 3405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3406 PetscValidPointer(support, 3); 3407 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3408 *support = &mesh->supports[off]; 3409 PetscFunctionReturn(0); 3410 } 3411 3412 /*@ 3413 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3414 3415 Not collective 3416 3417 Input Parameters: 3418 + mesh - The DMPlex 3419 . p - The point, which must lie in the chart set with DMPlexSetChart() 3420 - support - An array of points which are on the out-edges for point p 3421 3422 Output Parameter: 3423 3424 Note: 3425 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3426 3427 Level: beginner 3428 3429 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3430 @*/ 3431 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3432 { 3433 DM_Plex *mesh = (DM_Plex *)dm->data; 3434 PetscInt pStart, pEnd; 3435 PetscInt dof, off, c; 3436 3437 PetscFunctionBegin; 3438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3439 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3440 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3441 if (dof) PetscValidIntPointer(support, 3); 3442 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3443 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3444 for (c = 0; c < dof; ++c) { 3445 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3446 mesh->supports[off + c] = support[c]; 3447 } 3448 PetscFunctionReturn(0); 3449 } 3450 3451 /*@ 3452 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3453 3454 Not collective 3455 3456 Input Parameters: 3457 + mesh - The DMPlex 3458 . p - The point, which must lie in the chart set with DMPlexSetChart() 3459 . supportPos - The local index in the cone where the point should be put 3460 - supportPoint - The mesh point to insert 3461 3462 Level: beginner 3463 3464 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3465 @*/ 3466 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3467 { 3468 DM_Plex *mesh = (DM_Plex *)dm->data; 3469 PetscInt pStart, pEnd; 3470 PetscInt dof, off; 3471 3472 PetscFunctionBegin; 3473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3474 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3475 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3476 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3477 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3478 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3479 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3480 mesh->supports[off + supportPos] = supportPoint; 3481 PetscFunctionReturn(0); 3482 } 3483 3484 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3485 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3486 { 3487 switch (ct) { 3488 case DM_POLYTOPE_SEGMENT: 3489 if (o == -1) return -2; 3490 break; 3491 case DM_POLYTOPE_TRIANGLE: 3492 if (o == -3) return -1; 3493 if (o == -2) return -3; 3494 if (o == -1) return -2; 3495 break; 3496 case DM_POLYTOPE_QUADRILATERAL: 3497 if (o == -4) return -2; 3498 if (o == -3) return -1; 3499 if (o == -2) return -4; 3500 if (o == -1) return -3; 3501 break; 3502 default: 3503 return o; 3504 } 3505 return o; 3506 } 3507 3508 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3509 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3510 { 3511 switch (ct) { 3512 case DM_POLYTOPE_SEGMENT: 3513 if ((o == -2) || (o == 1)) return -1; 3514 if (o == -1) return 0; 3515 break; 3516 case DM_POLYTOPE_TRIANGLE: 3517 if (o == -3) return -2; 3518 if (o == -2) return -1; 3519 if (o == -1) return -3; 3520 break; 3521 case DM_POLYTOPE_QUADRILATERAL: 3522 if (o == -4) return -2; 3523 if (o == -3) return -1; 3524 if (o == -2) return -4; 3525 if (o == -1) return -3; 3526 break; 3527 default: 3528 return o; 3529 } 3530 return o; 3531 } 3532 3533 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3534 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3535 { 3536 PetscInt pStart, pEnd, p; 3537 3538 PetscFunctionBegin; 3539 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3540 for (p = pStart; p < pEnd; ++p) { 3541 const PetscInt *cone, *ornt; 3542 PetscInt coneSize, c; 3543 3544 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3545 PetscCall(DMPlexGetCone(dm, p, &cone)); 3546 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3547 for (c = 0; c < coneSize; ++c) { 3548 DMPolytopeType ct; 3549 const PetscInt o = ornt[c]; 3550 3551 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3552 switch (ct) { 3553 case DM_POLYTOPE_SEGMENT: 3554 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3555 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3556 break; 3557 case DM_POLYTOPE_TRIANGLE: 3558 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3559 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3560 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3561 break; 3562 case DM_POLYTOPE_QUADRILATERAL: 3563 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3564 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3565 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3566 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3567 break; 3568 default: 3569 break; 3570 } 3571 } 3572 } 3573 PetscFunctionReturn(0); 3574 } 3575 3576 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3577 { 3578 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3579 PetscInt *closure; 3580 const PetscInt *tmp = NULL, *tmpO = NULL; 3581 PetscInt off = 0, tmpSize, t; 3582 3583 PetscFunctionBeginHot; 3584 if (ornt) { 3585 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3586 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3587 } 3588 if (*points) { 3589 closure = *points; 3590 } else { 3591 PetscInt maxConeSize, maxSupportSize; 3592 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3593 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3594 } 3595 if (useCone) { 3596 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3597 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3598 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3599 } else { 3600 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3601 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3602 } 3603 if (ct == DM_POLYTOPE_UNKNOWN) { 3604 closure[off++] = p; 3605 closure[off++] = 0; 3606 for (t = 0; t < tmpSize; ++t) { 3607 closure[off++] = tmp[t]; 3608 closure[off++] = tmpO ? tmpO[t] : 0; 3609 } 3610 } else { 3611 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3612 3613 /* We assume that cells with a valid type have faces with a valid type */ 3614 closure[off++] = p; 3615 closure[off++] = ornt; 3616 for (t = 0; t < tmpSize; ++t) { 3617 DMPolytopeType ft; 3618 3619 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3620 closure[off++] = tmp[arr[t]]; 3621 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3622 } 3623 } 3624 if (numPoints) *numPoints = tmpSize + 1; 3625 if (points) *points = closure; 3626 PetscFunctionReturn(0); 3627 } 3628 3629 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3630 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3631 { 3632 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3633 const PetscInt *cone, *ornt; 3634 PetscInt *pts, *closure = NULL; 3635 DMPolytopeType ft; 3636 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3637 PetscInt dim, coneSize, c, d, clSize, cl; 3638 3639 PetscFunctionBeginHot; 3640 PetscCall(DMGetDimension(dm, &dim)); 3641 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3642 PetscCall(DMPlexGetCone(dm, point, &cone)); 3643 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3644 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3645 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3646 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3647 maxSize = PetscMax(coneSeries, supportSeries); 3648 if (*points) { 3649 pts = *points; 3650 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3651 c = 0; 3652 pts[c++] = point; 3653 pts[c++] = o; 3654 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3655 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3656 for (cl = 0; cl < clSize * 2; cl += 2) { 3657 pts[c++] = closure[cl]; 3658 pts[c++] = closure[cl + 1]; 3659 } 3660 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3661 for (cl = 0; cl < clSize * 2; cl += 2) { 3662 pts[c++] = closure[cl]; 3663 pts[c++] = closure[cl + 1]; 3664 } 3665 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3666 for (d = 2; d < coneSize; ++d) { 3667 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3668 pts[c++] = cone[arr[d * 2 + 0]]; 3669 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3670 } 3671 if (dim >= 3) { 3672 for (d = 2; d < coneSize; ++d) { 3673 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3674 const PetscInt *fcone, *fornt; 3675 PetscInt fconeSize, fc, i; 3676 3677 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3678 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3679 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3680 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3681 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3682 for (fc = 0; fc < fconeSize; ++fc) { 3683 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3684 const PetscInt co = farr[fc * 2 + 1]; 3685 3686 for (i = 0; i < c; i += 2) 3687 if (pts[i] == cp) break; 3688 if (i == c) { 3689 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3690 pts[c++] = cp; 3691 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3692 } 3693 } 3694 } 3695 } 3696 *numPoints = c / 2; 3697 *points = pts; 3698 PetscFunctionReturn(0); 3699 } 3700 3701 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3702 { 3703 DMPolytopeType ct; 3704 PetscInt *closure, *fifo; 3705 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3706 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3707 PetscInt depth, maxSize; 3708 3709 PetscFunctionBeginHot; 3710 PetscCall(DMPlexGetDepth(dm, &depth)); 3711 if (depth == 1) { 3712 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3713 PetscFunctionReturn(0); 3714 } 3715 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3716 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3717 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3718 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3719 PetscFunctionReturn(0); 3720 } 3721 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3722 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3723 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3724 maxSize = PetscMax(coneSeries, supportSeries); 3725 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3726 if (*points) { 3727 closure = *points; 3728 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3729 closure[closureSize++] = p; 3730 closure[closureSize++] = ornt; 3731 fifo[fifoSize++] = p; 3732 fifo[fifoSize++] = ornt; 3733 fifo[fifoSize++] = ct; 3734 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3735 while (fifoSize - fifoStart) { 3736 const PetscInt q = fifo[fifoStart++]; 3737 const PetscInt o = fifo[fifoStart++]; 3738 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3739 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3740 const PetscInt *tmp, *tmpO; 3741 PetscInt tmpSize, t; 3742 3743 if (PetscDefined(USE_DEBUG)) { 3744 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3745 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 3746 } 3747 if (useCone) { 3748 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3749 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3750 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3751 } else { 3752 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3753 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3754 tmpO = NULL; 3755 } 3756 for (t = 0; t < tmpSize; ++t) { 3757 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3758 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3759 const PetscInt cp = tmp[ip]; 3760 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3761 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3762 PetscInt c; 3763 3764 /* Check for duplicate */ 3765 for (c = 0; c < closureSize; c += 2) { 3766 if (closure[c] == cp) break; 3767 } 3768 if (c == closureSize) { 3769 closure[closureSize++] = cp; 3770 closure[closureSize++] = co; 3771 fifo[fifoSize++] = cp; 3772 fifo[fifoSize++] = co; 3773 fifo[fifoSize++] = ct; 3774 } 3775 } 3776 } 3777 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3778 if (numPoints) *numPoints = closureSize / 2; 3779 if (points) *points = closure; 3780 PetscFunctionReturn(0); 3781 } 3782 3783 /*@C 3784 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3785 3786 Not collective 3787 3788 Input Parameters: 3789 + dm - The DMPlex 3790 . p - The mesh point 3791 - useCone - PETSC_TRUE for the closure, otherwise return the star 3792 3793 Input/Output Parameter: 3794 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3795 if NULL on input, internal storage will be returned, otherwise the provided array is used 3796 3797 Output Parameter: 3798 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3799 3800 Note: 3801 If using internal storage (points is NULL on input), each call overwrites the last output. 3802 3803 Fortran Note: 3804 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3805 3806 Level: beginner 3807 3808 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3809 @*/ 3810 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3811 { 3812 PetscFunctionBeginHot; 3813 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3814 if (numPoints) PetscValidIntPointer(numPoints, 4); 3815 if (points) PetscValidPointer(points, 5); 3816 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3817 PetscFunctionReturn(0); 3818 } 3819 3820 /*@C 3821 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3822 3823 Not collective 3824 3825 Input Parameters: 3826 + dm - The DMPlex 3827 . p - The mesh point 3828 . useCone - PETSC_TRUE for the closure, otherwise return the star 3829 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3830 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3831 3832 Note: 3833 If not using internal storage (points is not NULL on input), this call is unnecessary 3834 3835 Level: beginner 3836 3837 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3838 @*/ 3839 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3840 { 3841 PetscFunctionBeginHot; 3842 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3843 if (numPoints) *numPoints = 0; 3844 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3845 PetscFunctionReturn(0); 3846 } 3847 3848 /*@ 3849 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3850 3851 Not collective 3852 3853 Input Parameter: 3854 . mesh - The DMPlex 3855 3856 Output Parameters: 3857 + maxConeSize - The maximum number of in-edges 3858 - maxSupportSize - The maximum number of out-edges 3859 3860 Level: beginner 3861 3862 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3863 @*/ 3864 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3865 { 3866 DM_Plex *mesh = (DM_Plex *)dm->data; 3867 3868 PetscFunctionBegin; 3869 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3870 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3871 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3872 PetscFunctionReturn(0); 3873 } 3874 3875 PetscErrorCode DMSetUp_Plex(DM dm) 3876 { 3877 DM_Plex *mesh = (DM_Plex *)dm->data; 3878 PetscInt size, maxSupportSize; 3879 3880 PetscFunctionBegin; 3881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3882 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3883 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3884 PetscCall(PetscMalloc1(size, &mesh->cones)); 3885 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3886 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3887 if (maxSupportSize) { 3888 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3889 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3890 PetscCall(PetscMalloc1(size, &mesh->supports)); 3891 } 3892 PetscFunctionReturn(0); 3893 } 3894 3895 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3896 { 3897 PetscFunctionBegin; 3898 if (subdm) PetscCall(DMClone(dm, subdm)); 3899 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3900 if (subdm) (*subdm)->useNatural = dm->useNatural; 3901 if (dm->useNatural && dm->sfMigration) { 3902 PetscSF sfNatural; 3903 3904 (*subdm)->sfMigration = dm->sfMigration; 3905 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3906 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3907 (*subdm)->sfNatural = sfNatural; 3908 } 3909 PetscFunctionReturn(0); 3910 } 3911 3912 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3913 { 3914 PetscInt i = 0; 3915 3916 PetscFunctionBegin; 3917 PetscCall(DMClone(dms[0], superdm)); 3918 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3919 (*superdm)->useNatural = PETSC_FALSE; 3920 for (i = 0; i < len; i++) { 3921 if (dms[i]->useNatural && dms[i]->sfMigration) { 3922 PetscSF sfNatural; 3923 3924 (*superdm)->sfMigration = dms[i]->sfMigration; 3925 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3926 (*superdm)->useNatural = PETSC_TRUE; 3927 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3928 (*superdm)->sfNatural = sfNatural; 3929 break; 3930 } 3931 } 3932 PetscFunctionReturn(0); 3933 } 3934 3935 /*@ 3936 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3937 3938 Not collective 3939 3940 Input Parameter: 3941 . mesh - The DMPlex 3942 3943 Output Parameter: 3944 3945 Note: 3946 This should be called after all calls to DMPlexSetCone() 3947 3948 Level: beginner 3949 3950 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3951 @*/ 3952 PetscErrorCode DMPlexSymmetrize(DM dm) 3953 { 3954 DM_Plex *mesh = (DM_Plex *)dm->data; 3955 PetscInt *offsets; 3956 PetscInt supportSize; 3957 PetscInt pStart, pEnd, p; 3958 3959 PetscFunctionBegin; 3960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3961 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3962 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3963 /* Calculate support sizes */ 3964 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3965 for (p = pStart; p < pEnd; ++p) { 3966 PetscInt dof, off, c; 3967 3968 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3969 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3970 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3971 } 3972 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3973 /* Calculate supports */ 3974 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3975 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3976 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3977 for (p = pStart; p < pEnd; ++p) { 3978 PetscInt dof, off, c; 3979 3980 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3981 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3982 for (c = off; c < off + dof; ++c) { 3983 const PetscInt q = mesh->cones[c]; 3984 PetscInt offS; 3985 3986 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3987 3988 mesh->supports[offS + offsets[q]] = p; 3989 ++offsets[q]; 3990 } 3991 } 3992 PetscCall(PetscFree(offsets)); 3993 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3994 PetscFunctionReturn(0); 3995 } 3996 3997 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3998 { 3999 IS stratumIS; 4000 4001 PetscFunctionBegin; 4002 if (pStart >= pEnd) PetscFunctionReturn(0); 4003 if (PetscDefined(USE_DEBUG)) { 4004 PetscInt qStart, qEnd, numLevels, level; 4005 PetscBool overlap = PETSC_FALSE; 4006 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4007 for (level = 0; level < numLevels; level++) { 4008 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4009 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4010 overlap = PETSC_TRUE; 4011 break; 4012 } 4013 } 4014 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 4015 } 4016 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4017 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4018 PetscCall(ISDestroy(&stratumIS)); 4019 PetscFunctionReturn(0); 4020 } 4021 4022 /*@ 4023 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4024 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 4025 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 4026 the DAG. 4027 4028 Collective on dm 4029 4030 Input Parameter: 4031 . mesh - The DMPlex 4032 4033 Output Parameter: 4034 4035 Notes: 4036 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4037 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4038 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 4039 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 4040 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 4041 4042 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4043 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4044 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 4045 to interpolate only that one (e0), so that 4046 $ cone(c0) = {e0, v2} 4047 $ cone(e0) = {v0, v1} 4048 If DMPlexStratify() is run on this mesh, it will give depths 4049 $ depth 0 = {v0, v1, v2} 4050 $ depth 1 = {e0, c0} 4051 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4052 4053 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 4054 4055 Level: beginner 4056 4057 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4058 @*/ 4059 PetscErrorCode DMPlexStratify(DM dm) 4060 { 4061 DM_Plex *mesh = (DM_Plex *)dm->data; 4062 DMLabel label; 4063 PetscInt pStart, pEnd, p; 4064 PetscInt numRoots = 0, numLeaves = 0; 4065 4066 PetscFunctionBegin; 4067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4068 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4069 4070 /* Create depth label */ 4071 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4072 PetscCall(DMCreateLabel(dm, "depth")); 4073 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4074 4075 { 4076 /* Initialize roots and count leaves */ 4077 PetscInt sMin = PETSC_MAX_INT; 4078 PetscInt sMax = PETSC_MIN_INT; 4079 PetscInt coneSize, supportSize; 4080 4081 for (p = pStart; p < pEnd; ++p) { 4082 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4083 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4084 if (!coneSize && supportSize) { 4085 sMin = PetscMin(p, sMin); 4086 sMax = PetscMax(p, sMax); 4087 ++numRoots; 4088 } else if (!supportSize && coneSize) { 4089 ++numLeaves; 4090 } else if (!supportSize && !coneSize) { 4091 /* Isolated points */ 4092 sMin = PetscMin(p, sMin); 4093 sMax = PetscMax(p, sMax); 4094 } 4095 } 4096 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4097 } 4098 4099 if (numRoots + numLeaves == (pEnd - pStart)) { 4100 PetscInt sMin = PETSC_MAX_INT; 4101 PetscInt sMax = PETSC_MIN_INT; 4102 PetscInt coneSize, supportSize; 4103 4104 for (p = pStart; p < pEnd; ++p) { 4105 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4106 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4107 if (!supportSize && coneSize) { 4108 sMin = PetscMin(p, sMin); 4109 sMax = PetscMax(p, sMax); 4110 } 4111 } 4112 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4113 } else { 4114 PetscInt level = 0; 4115 PetscInt qStart, qEnd, q; 4116 4117 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4118 while (qEnd > qStart) { 4119 PetscInt sMin = PETSC_MAX_INT; 4120 PetscInt sMax = PETSC_MIN_INT; 4121 4122 for (q = qStart; q < qEnd; ++q) { 4123 const PetscInt *support; 4124 PetscInt supportSize, s; 4125 4126 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4127 PetscCall(DMPlexGetSupport(dm, q, &support)); 4128 for (s = 0; s < supportSize; ++s) { 4129 sMin = PetscMin(support[s], sMin); 4130 sMax = PetscMax(support[s], sMax); 4131 } 4132 } 4133 PetscCall(DMLabelGetNumValues(label, &level)); 4134 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4135 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4136 } 4137 } 4138 { /* just in case there is an empty process */ 4139 PetscInt numValues, maxValues = 0, v; 4140 4141 PetscCall(DMLabelGetNumValues(label, &numValues)); 4142 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4143 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4144 } 4145 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4146 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4147 PetscFunctionReturn(0); 4148 } 4149 4150 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4151 { 4152 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4153 PetscInt dim, depth, pheight, coneSize; 4154 4155 PetscFunctionBeginHot; 4156 PetscCall(DMGetDimension(dm, &dim)); 4157 PetscCall(DMPlexGetDepth(dm, &depth)); 4158 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4159 pheight = depth - pdepth; 4160 if (depth <= 1) { 4161 switch (pdepth) { 4162 case 0: 4163 ct = DM_POLYTOPE_POINT; 4164 break; 4165 case 1: 4166 switch (coneSize) { 4167 case 2: 4168 ct = DM_POLYTOPE_SEGMENT; 4169 break; 4170 case 3: 4171 ct = DM_POLYTOPE_TRIANGLE; 4172 break; 4173 case 4: 4174 switch (dim) { 4175 case 2: 4176 ct = DM_POLYTOPE_QUADRILATERAL; 4177 break; 4178 case 3: 4179 ct = DM_POLYTOPE_TETRAHEDRON; 4180 break; 4181 default: 4182 break; 4183 } 4184 break; 4185 case 5: 4186 ct = DM_POLYTOPE_PYRAMID; 4187 break; 4188 case 6: 4189 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4190 break; 4191 case 8: 4192 ct = DM_POLYTOPE_HEXAHEDRON; 4193 break; 4194 default: 4195 break; 4196 } 4197 } 4198 } else { 4199 if (pdepth == 0) { 4200 ct = DM_POLYTOPE_POINT; 4201 } else if (pheight == 0) { 4202 switch (dim) { 4203 case 1: 4204 switch (coneSize) { 4205 case 2: 4206 ct = DM_POLYTOPE_SEGMENT; 4207 break; 4208 default: 4209 break; 4210 } 4211 break; 4212 case 2: 4213 switch (coneSize) { 4214 case 3: 4215 ct = DM_POLYTOPE_TRIANGLE; 4216 break; 4217 case 4: 4218 ct = DM_POLYTOPE_QUADRILATERAL; 4219 break; 4220 default: 4221 break; 4222 } 4223 break; 4224 case 3: 4225 switch (coneSize) { 4226 case 4: 4227 ct = DM_POLYTOPE_TETRAHEDRON; 4228 break; 4229 case 5: { 4230 const PetscInt *cone; 4231 PetscInt faceConeSize; 4232 4233 PetscCall(DMPlexGetCone(dm, p, &cone)); 4234 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4235 switch (faceConeSize) { 4236 case 3: 4237 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4238 break; 4239 case 4: 4240 ct = DM_POLYTOPE_PYRAMID; 4241 break; 4242 } 4243 } break; 4244 case 6: 4245 ct = DM_POLYTOPE_HEXAHEDRON; 4246 break; 4247 default: 4248 break; 4249 } 4250 break; 4251 default: 4252 break; 4253 } 4254 } else if (pheight > 0) { 4255 switch (coneSize) { 4256 case 2: 4257 ct = DM_POLYTOPE_SEGMENT; 4258 break; 4259 case 3: 4260 ct = DM_POLYTOPE_TRIANGLE; 4261 break; 4262 case 4: 4263 ct = DM_POLYTOPE_QUADRILATERAL; 4264 break; 4265 default: 4266 break; 4267 } 4268 } 4269 } 4270 *pt = ct; 4271 PetscFunctionReturn(0); 4272 } 4273 4274 /*@ 4275 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4276 4277 Collective on dm 4278 4279 Input Parameter: 4280 . mesh - The DMPlex 4281 4282 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4283 4284 Level: developer 4285 4286 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4287 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4288 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4289 4290 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4291 @*/ 4292 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4293 { 4294 DM_Plex *mesh; 4295 DMLabel ctLabel; 4296 PetscInt pStart, pEnd, p; 4297 4298 PetscFunctionBegin; 4299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4300 mesh = (DM_Plex *)dm->data; 4301 PetscCall(DMCreateLabel(dm, "celltype")); 4302 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4303 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4304 for (p = pStart; p < pEnd; ++p) { 4305 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4306 PetscInt pdepth; 4307 4308 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4309 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4310 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4311 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4312 } 4313 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4314 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4315 PetscFunctionReturn(0); 4316 } 4317 4318 /*@C 4319 DMPlexGetJoin - Get an array for the join of the set of points 4320 4321 Not Collective 4322 4323 Input Parameters: 4324 + dm - The DMPlex object 4325 . numPoints - The number of input points for the join 4326 - points - The input points 4327 4328 Output Parameters: 4329 + numCoveredPoints - The number of points in the join 4330 - coveredPoints - The points in the join 4331 4332 Level: intermediate 4333 4334 Note: Currently, this is restricted to a single level join 4335 4336 Fortran Notes: 4337 Since it returns an array, this routine is only available in Fortran 90, and you must 4338 include petsc.h90 in your code. 4339 4340 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4341 4342 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4343 @*/ 4344 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4345 { 4346 DM_Plex *mesh = (DM_Plex *)dm->data; 4347 PetscInt *join[2]; 4348 PetscInt joinSize, i = 0; 4349 PetscInt dof, off, p, c, m; 4350 PetscInt maxSupportSize; 4351 4352 PetscFunctionBegin; 4353 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4354 PetscValidIntPointer(points, 3); 4355 PetscValidIntPointer(numCoveredPoints, 4); 4356 PetscValidPointer(coveredPoints, 5); 4357 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4358 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4359 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4360 /* Copy in support of first point */ 4361 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4362 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4363 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4364 /* Check each successive support */ 4365 for (p = 1; p < numPoints; ++p) { 4366 PetscInt newJoinSize = 0; 4367 4368 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4369 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4370 for (c = 0; c < dof; ++c) { 4371 const PetscInt point = mesh->supports[off + c]; 4372 4373 for (m = 0; m < joinSize; ++m) { 4374 if (point == join[i][m]) { 4375 join[1 - i][newJoinSize++] = point; 4376 break; 4377 } 4378 } 4379 } 4380 joinSize = newJoinSize; 4381 i = 1 - i; 4382 } 4383 *numCoveredPoints = joinSize; 4384 *coveredPoints = join[i]; 4385 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4386 PetscFunctionReturn(0); 4387 } 4388 4389 /*@C 4390 DMPlexRestoreJoin - Restore an array for the join of the set of points 4391 4392 Not Collective 4393 4394 Input Parameters: 4395 + dm - The DMPlex object 4396 . numPoints - The number of input points for the join 4397 - points - The input points 4398 4399 Output Parameters: 4400 + numCoveredPoints - The number of points in the join 4401 - coveredPoints - The points in the join 4402 4403 Fortran Notes: 4404 Since it returns an array, this routine is only available in Fortran 90, and you must 4405 include petsc.h90 in your code. 4406 4407 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4408 4409 Level: intermediate 4410 4411 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4412 @*/ 4413 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4414 { 4415 PetscFunctionBegin; 4416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4417 if (points) PetscValidIntPointer(points, 3); 4418 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4419 PetscValidPointer(coveredPoints, 5); 4420 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4421 if (numCoveredPoints) *numCoveredPoints = 0; 4422 PetscFunctionReturn(0); 4423 } 4424 4425 /*@C 4426 DMPlexGetFullJoin - Get an array for the join of the set of points 4427 4428 Not Collective 4429 4430 Input Parameters: 4431 + dm - The DMPlex object 4432 . numPoints - The number of input points for the join 4433 - points - The input points 4434 4435 Output Parameters: 4436 + numCoveredPoints - The number of points in the join 4437 - coveredPoints - The points in the join 4438 4439 Fortran Notes: 4440 Since it returns an array, this routine is only available in Fortran 90, and you must 4441 include petsc.h90 in your code. 4442 4443 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4444 4445 Level: intermediate 4446 4447 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4448 @*/ 4449 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4450 { 4451 PetscInt *offsets, **closures; 4452 PetscInt *join[2]; 4453 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4454 PetscInt p, d, c, m, ms; 4455 4456 PetscFunctionBegin; 4457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4458 PetscValidIntPointer(points, 3); 4459 PetscValidIntPointer(numCoveredPoints, 4); 4460 PetscValidPointer(coveredPoints, 5); 4461 4462 PetscCall(DMPlexGetDepth(dm, &depth)); 4463 PetscCall(PetscCalloc1(numPoints, &closures)); 4464 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4465 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4466 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4467 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4468 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4469 4470 for (p = 0; p < numPoints; ++p) { 4471 PetscInt closureSize; 4472 4473 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4474 4475 offsets[p * (depth + 2) + 0] = 0; 4476 for (d = 0; d < depth + 1; ++d) { 4477 PetscInt pStart, pEnd, i; 4478 4479 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4480 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4481 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4482 offsets[p * (depth + 2) + d + 1] = i; 4483 break; 4484 } 4485 } 4486 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4487 } 4488 PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize); 4489 } 4490 for (d = 0; d < depth + 1; ++d) { 4491 PetscInt dof; 4492 4493 /* Copy in support of first point */ 4494 dof = offsets[d + 1] - offsets[d]; 4495 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4496 /* Check each successive cone */ 4497 for (p = 1; p < numPoints && joinSize; ++p) { 4498 PetscInt newJoinSize = 0; 4499 4500 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4501 for (c = 0; c < dof; ++c) { 4502 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4503 4504 for (m = 0; m < joinSize; ++m) { 4505 if (point == join[i][m]) { 4506 join[1 - i][newJoinSize++] = point; 4507 break; 4508 } 4509 } 4510 } 4511 joinSize = newJoinSize; 4512 i = 1 - i; 4513 } 4514 if (joinSize) break; 4515 } 4516 *numCoveredPoints = joinSize; 4517 *coveredPoints = join[i]; 4518 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4519 PetscCall(PetscFree(closures)); 4520 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4521 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4522 PetscFunctionReturn(0); 4523 } 4524 4525 /*@C 4526 DMPlexGetMeet - Get an array for the meet of the set of points 4527 4528 Not Collective 4529 4530 Input Parameters: 4531 + dm - The DMPlex object 4532 . numPoints - The number of input points for the meet 4533 - points - The input points 4534 4535 Output Parameters: 4536 + numCoveredPoints - The number of points in the meet 4537 - coveredPoints - The points in the meet 4538 4539 Level: intermediate 4540 4541 Note: Currently, this is restricted to a single level meet 4542 4543 Fortran Notes: 4544 Since it returns an array, this routine is only available in Fortran 90, and you must 4545 include petsc.h90 in your code. 4546 4547 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4548 4549 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4550 @*/ 4551 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4552 { 4553 DM_Plex *mesh = (DM_Plex *)dm->data; 4554 PetscInt *meet[2]; 4555 PetscInt meetSize, i = 0; 4556 PetscInt dof, off, p, c, m; 4557 PetscInt maxConeSize; 4558 4559 PetscFunctionBegin; 4560 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4561 PetscValidIntPointer(points, 3); 4562 PetscValidIntPointer(numCoveringPoints, 4); 4563 PetscValidPointer(coveringPoints, 5); 4564 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4565 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4566 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4567 /* Copy in cone of first point */ 4568 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4569 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4570 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4571 /* Check each successive cone */ 4572 for (p = 1; p < numPoints; ++p) { 4573 PetscInt newMeetSize = 0; 4574 4575 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4576 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4577 for (c = 0; c < dof; ++c) { 4578 const PetscInt point = mesh->cones[off + c]; 4579 4580 for (m = 0; m < meetSize; ++m) { 4581 if (point == meet[i][m]) { 4582 meet[1 - i][newMeetSize++] = point; 4583 break; 4584 } 4585 } 4586 } 4587 meetSize = newMeetSize; 4588 i = 1 - i; 4589 } 4590 *numCoveringPoints = meetSize; 4591 *coveringPoints = meet[i]; 4592 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4593 PetscFunctionReturn(0); 4594 } 4595 4596 /*@C 4597 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4598 4599 Not Collective 4600 4601 Input Parameters: 4602 + dm - The DMPlex object 4603 . numPoints - The number of input points for the meet 4604 - points - The input points 4605 4606 Output Parameters: 4607 + numCoveredPoints - The number of points in the meet 4608 - coveredPoints - The points in the meet 4609 4610 Level: intermediate 4611 4612 Fortran Notes: 4613 Since it returns an array, this routine is only available in Fortran 90, and you must 4614 include petsc.h90 in your code. 4615 4616 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4617 4618 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4619 @*/ 4620 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4621 { 4622 PetscFunctionBegin; 4623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4624 if (points) PetscValidIntPointer(points, 3); 4625 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4626 PetscValidPointer(coveredPoints, 5); 4627 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4628 if (numCoveredPoints) *numCoveredPoints = 0; 4629 PetscFunctionReturn(0); 4630 } 4631 4632 /*@C 4633 DMPlexGetFullMeet - Get an array for the meet of the set of points 4634 4635 Not Collective 4636 4637 Input Parameters: 4638 + dm - The DMPlex object 4639 . numPoints - The number of input points for the meet 4640 - points - The input points 4641 4642 Output Parameters: 4643 + numCoveredPoints - The number of points in the meet 4644 - coveredPoints - The points in the meet 4645 4646 Level: intermediate 4647 4648 Fortran Notes: 4649 Since it returns an array, this routine is only available in Fortran 90, and you must 4650 include petsc.h90 in your code. 4651 4652 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4653 4654 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4655 @*/ 4656 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4657 { 4658 PetscInt *offsets, **closures; 4659 PetscInt *meet[2]; 4660 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4661 PetscInt p, h, c, m, mc; 4662 4663 PetscFunctionBegin; 4664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4665 PetscValidIntPointer(points, 3); 4666 PetscValidIntPointer(numCoveredPoints, 4); 4667 PetscValidPointer(coveredPoints, 5); 4668 4669 PetscCall(DMPlexGetDepth(dm, &height)); 4670 PetscCall(PetscMalloc1(numPoints, &closures)); 4671 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4672 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4673 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4674 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4675 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4676 4677 for (p = 0; p < numPoints; ++p) { 4678 PetscInt closureSize; 4679 4680 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4681 4682 offsets[p * (height + 2) + 0] = 0; 4683 for (h = 0; h < height + 1; ++h) { 4684 PetscInt pStart, pEnd, i; 4685 4686 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4687 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4688 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4689 offsets[p * (height + 2) + h + 1] = i; 4690 break; 4691 } 4692 } 4693 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4694 } 4695 PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize); 4696 } 4697 for (h = 0; h < height + 1; ++h) { 4698 PetscInt dof; 4699 4700 /* Copy in cone of first point */ 4701 dof = offsets[h + 1] - offsets[h]; 4702 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4703 /* Check each successive cone */ 4704 for (p = 1; p < numPoints && meetSize; ++p) { 4705 PetscInt newMeetSize = 0; 4706 4707 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4708 for (c = 0; c < dof; ++c) { 4709 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4710 4711 for (m = 0; m < meetSize; ++m) { 4712 if (point == meet[i][m]) { 4713 meet[1 - i][newMeetSize++] = point; 4714 break; 4715 } 4716 } 4717 } 4718 meetSize = newMeetSize; 4719 i = 1 - i; 4720 } 4721 if (meetSize) break; 4722 } 4723 *numCoveredPoints = meetSize; 4724 *coveredPoints = meet[i]; 4725 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4726 PetscCall(PetscFree(closures)); 4727 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4728 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4729 PetscFunctionReturn(0); 4730 } 4731 4732 /*@C 4733 DMPlexEqual - Determine if two DMs have the same topology 4734 4735 Not Collective 4736 4737 Input Parameters: 4738 + dmA - A DMPlex object 4739 - dmB - A DMPlex object 4740 4741 Output Parameters: 4742 . equal - PETSC_TRUE if the topologies are identical 4743 4744 Level: intermediate 4745 4746 Notes: 4747 We are not solving graph isomorphism, so we do not permutation. 4748 4749 .seealso: `DMPlexGetCone()` 4750 @*/ 4751 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4752 { 4753 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4754 4755 PetscFunctionBegin; 4756 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4757 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4758 PetscValidBoolPointer(equal, 3); 4759 4760 *equal = PETSC_FALSE; 4761 PetscCall(DMPlexGetDepth(dmA, &depth)); 4762 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4763 if (depth != depthB) PetscFunctionReturn(0); 4764 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4765 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4766 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4767 for (p = pStart; p < pEnd; ++p) { 4768 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4769 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4770 4771 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4772 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4773 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4774 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4775 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4776 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4777 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4778 for (c = 0; c < coneSize; ++c) { 4779 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4780 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4781 } 4782 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4783 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4784 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4785 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4786 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4787 for (s = 0; s < supportSize; ++s) { 4788 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4789 } 4790 } 4791 *equal = PETSC_TRUE; 4792 PetscFunctionReturn(0); 4793 } 4794 4795 /*@C 4796 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4797 4798 Not Collective 4799 4800 Input Parameters: 4801 + dm - The DMPlex 4802 . cellDim - The cell dimension 4803 - numCorners - The number of vertices on a cell 4804 4805 Output Parameters: 4806 . numFaceVertices - The number of vertices on a face 4807 4808 Level: developer 4809 4810 Notes: 4811 Of course this can only work for a restricted set of symmetric shapes 4812 4813 .seealso: `DMPlexGetCone()` 4814 @*/ 4815 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4816 { 4817 MPI_Comm comm; 4818 4819 PetscFunctionBegin; 4820 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4821 PetscValidIntPointer(numFaceVertices, 4); 4822 switch (cellDim) { 4823 case 0: 4824 *numFaceVertices = 0; 4825 break; 4826 case 1: 4827 *numFaceVertices = 1; 4828 break; 4829 case 2: 4830 switch (numCorners) { 4831 case 3: /* triangle */ 4832 *numFaceVertices = 2; /* Edge has 2 vertices */ 4833 break; 4834 case 4: /* quadrilateral */ 4835 *numFaceVertices = 2; /* Edge has 2 vertices */ 4836 break; 4837 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4838 *numFaceVertices = 3; /* Edge has 3 vertices */ 4839 break; 4840 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4841 *numFaceVertices = 3; /* Edge has 3 vertices */ 4842 break; 4843 default: 4844 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4845 } 4846 break; 4847 case 3: 4848 switch (numCorners) { 4849 case 4: /* tetradehdron */ 4850 *numFaceVertices = 3; /* Face has 3 vertices */ 4851 break; 4852 case 6: /* tet cohesive cells */ 4853 *numFaceVertices = 4; /* Face has 4 vertices */ 4854 break; 4855 case 8: /* hexahedron */ 4856 *numFaceVertices = 4; /* Face has 4 vertices */ 4857 break; 4858 case 9: /* tet cohesive Lagrange cells */ 4859 *numFaceVertices = 6; /* Face has 6 vertices */ 4860 break; 4861 case 10: /* quadratic tetrahedron */ 4862 *numFaceVertices = 6; /* Face has 6 vertices */ 4863 break; 4864 case 12: /* hex cohesive Lagrange cells */ 4865 *numFaceVertices = 6; /* Face has 6 vertices */ 4866 break; 4867 case 18: /* quadratic tet cohesive Lagrange cells */ 4868 *numFaceVertices = 6; /* Face has 6 vertices */ 4869 break; 4870 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4871 *numFaceVertices = 9; /* Face has 9 vertices */ 4872 break; 4873 default: 4874 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4875 } 4876 break; 4877 default: 4878 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4879 } 4880 PetscFunctionReturn(0); 4881 } 4882 4883 /*@ 4884 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4885 4886 Not Collective 4887 4888 Input Parameter: 4889 . dm - The DMPlex object 4890 4891 Output Parameter: 4892 . depthLabel - The DMLabel recording point depth 4893 4894 Level: developer 4895 4896 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4897 @*/ 4898 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4899 { 4900 PetscFunctionBegin; 4901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4902 PetscValidPointer(depthLabel, 2); 4903 *depthLabel = dm->depthLabel; 4904 PetscFunctionReturn(0); 4905 } 4906 4907 /*@ 4908 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4909 4910 Not Collective 4911 4912 Input Parameter: 4913 . dm - The DMPlex object 4914 4915 Output Parameter: 4916 . depth - The number of strata (breadth first levels) in the DAG 4917 4918 Level: developer 4919 4920 Notes: 4921 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4922 The point depth is described more in detail in DMPlexGetDepthStratum(). 4923 An empty mesh gives -1. 4924 4925 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4926 @*/ 4927 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4928 { 4929 DM_Plex *mesh = (DM_Plex *)dm->data; 4930 DMLabel label; 4931 PetscInt d = 0; 4932 4933 PetscFunctionBegin; 4934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4935 PetscValidIntPointer(depth, 2); 4936 if (mesh->tr) { 4937 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 4938 } else { 4939 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4940 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4941 *depth = d - 1; 4942 } 4943 PetscFunctionReturn(0); 4944 } 4945 4946 /*@ 4947 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4948 4949 Not Collective 4950 4951 Input Parameters: 4952 + dm - The DMPlex object 4953 - depth - The requested depth 4954 4955 Output Parameters: 4956 + start - The first point at this depth 4957 - end - One beyond the last point at this depth 4958 4959 Notes: 4960 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4961 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4962 higher dimension, e.g., "edges". 4963 4964 Level: developer 4965 4966 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4967 @*/ 4968 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4969 { 4970 DM_Plex *mesh = (DM_Plex *)dm->data; 4971 DMLabel label; 4972 PetscInt pStart, pEnd; 4973 4974 PetscFunctionBegin; 4975 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4976 if (start) { 4977 PetscValidIntPointer(start, 3); 4978 *start = 0; 4979 } 4980 if (end) { 4981 PetscValidIntPointer(end, 4); 4982 *end = 0; 4983 } 4984 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4985 if (pStart == pEnd) PetscFunctionReturn(0); 4986 if (depth < 0) { 4987 if (start) *start = pStart; 4988 if (end) *end = pEnd; 4989 PetscFunctionReturn(0); 4990 } 4991 if (mesh->tr) { 4992 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 4993 } else { 4994 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4995 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4996 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4997 } 4998 PetscFunctionReturn(0); 4999 } 5000 5001 /*@ 5002 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 5003 5004 Not Collective 5005 5006 Input Parameters: 5007 + dm - The DMPlex object 5008 - height - The requested height 5009 5010 Output Parameters: 5011 + start - The first point at this height 5012 - end - One beyond the last point at this height 5013 5014 Notes: 5015 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5016 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 5017 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5018 5019 Level: developer 5020 5021 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5022 @*/ 5023 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5024 { 5025 DMLabel label; 5026 PetscInt depth, pStart, pEnd; 5027 5028 PetscFunctionBegin; 5029 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5030 if (start) { 5031 PetscValidIntPointer(start, 3); 5032 *start = 0; 5033 } 5034 if (end) { 5035 PetscValidIntPointer(end, 4); 5036 *end = 0; 5037 } 5038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5039 if (pStart == pEnd) PetscFunctionReturn(0); 5040 if (height < 0) { 5041 if (start) *start = pStart; 5042 if (end) *end = pEnd; 5043 PetscFunctionReturn(0); 5044 } 5045 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5046 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5047 PetscCall(DMLabelGetNumValues(label, &depth)); 5048 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 5049 PetscFunctionReturn(0); 5050 } 5051 5052 /*@ 5053 DMPlexGetPointDepth - Get the depth of a given point 5054 5055 Not Collective 5056 5057 Input Parameters: 5058 + dm - The DMPlex object 5059 - point - The point 5060 5061 Output Parameter: 5062 . depth - The depth of the point 5063 5064 Level: intermediate 5065 5066 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5067 @*/ 5068 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5069 { 5070 PetscFunctionBegin; 5071 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5072 PetscValidIntPointer(depth, 3); 5073 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5074 PetscFunctionReturn(0); 5075 } 5076 5077 /*@ 5078 DMPlexGetPointHeight - Get the height of a given point 5079 5080 Not Collective 5081 5082 Input Parameters: 5083 + dm - The DMPlex object 5084 - point - The point 5085 5086 Output Parameter: 5087 . height - The height of the point 5088 5089 Level: intermediate 5090 5091 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5092 @*/ 5093 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5094 { 5095 PetscInt n, pDepth; 5096 5097 PetscFunctionBegin; 5098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5099 PetscValidIntPointer(height, 3); 5100 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5101 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5102 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5103 PetscFunctionReturn(0); 5104 } 5105 5106 /*@ 5107 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 5108 5109 Not Collective 5110 5111 Input Parameter: 5112 . dm - The DMPlex object 5113 5114 Output Parameter: 5115 . celltypeLabel - The DMLabel recording cell polytope type 5116 5117 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 5118 DMCreateLabel(dm, "celltype") beforehand. 5119 5120 Level: developer 5121 5122 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5123 @*/ 5124 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5125 { 5126 PetscFunctionBegin; 5127 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5128 PetscValidPointer(celltypeLabel, 2); 5129 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5130 *celltypeLabel = dm->celltypeLabel; 5131 PetscFunctionReturn(0); 5132 } 5133 5134 /*@ 5135 DMPlexGetCellType - Get the polytope type of a given cell 5136 5137 Not Collective 5138 5139 Input Parameters: 5140 + dm - The DMPlex object 5141 - cell - The cell 5142 5143 Output Parameter: 5144 . celltype - The polytope type of the cell 5145 5146 Level: intermediate 5147 5148 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5149 @*/ 5150 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5151 { 5152 DM_Plex *mesh = (DM_Plex *)dm->data; 5153 DMLabel label; 5154 PetscInt ct; 5155 5156 PetscFunctionBegin; 5157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5158 PetscValidPointer(celltype, 3); 5159 if (mesh->tr) { 5160 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5161 } else { 5162 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5163 PetscCall(DMLabelGetValue(label, cell, &ct)); 5164 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5165 *celltype = (DMPolytopeType)ct; 5166 } 5167 PetscFunctionReturn(0); 5168 } 5169 5170 /*@ 5171 DMPlexSetCellType - Set the polytope type of a given cell 5172 5173 Not Collective 5174 5175 Input Parameters: 5176 + dm - The DMPlex object 5177 . cell - The cell 5178 - celltype - The polytope type of the cell 5179 5180 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5181 is executed. This function will override the computed type. However, if automatic classification will not succeed 5182 and a user wants to manually specify all types, the classification must be disabled by calling 5183 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5184 5185 Level: advanced 5186 5187 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5188 @*/ 5189 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5190 { 5191 DMLabel label; 5192 5193 PetscFunctionBegin; 5194 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5195 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5196 PetscCall(DMLabelSetValue(label, cell, celltype)); 5197 PetscFunctionReturn(0); 5198 } 5199 5200 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5201 { 5202 PetscSection section, s; 5203 Mat m; 5204 PetscInt maxHeight; 5205 5206 PetscFunctionBegin; 5207 PetscCall(DMClone(dm, cdm)); 5208 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5209 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5210 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5211 PetscCall(DMSetLocalSection(*cdm, section)); 5212 PetscCall(PetscSectionDestroy(§ion)); 5213 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5214 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5215 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5216 PetscCall(PetscSectionDestroy(&s)); 5217 PetscCall(MatDestroy(&m)); 5218 5219 PetscCall(DMSetNumFields(*cdm, 1)); 5220 PetscCall(DMCreateDS(*cdm)); 5221 PetscFunctionReturn(0); 5222 } 5223 5224 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5225 { 5226 Vec coordsLocal, cellCoordsLocal; 5227 DM coordsDM, cellCoordsDM; 5228 5229 PetscFunctionBegin; 5230 *field = NULL; 5231 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5232 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5233 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5234 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5235 if (coordsLocal && coordsDM) { 5236 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5237 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5238 } 5239 PetscFunctionReturn(0); 5240 } 5241 5242 /*@C 5243 DMPlexGetConeSection - Return a section which describes the layout of cone data 5244 5245 Not Collective 5246 5247 Input Parameters: 5248 . dm - The DMPlex object 5249 5250 Output Parameter: 5251 . section - The PetscSection object 5252 5253 Level: developer 5254 5255 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5256 @*/ 5257 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5258 { 5259 DM_Plex *mesh = (DM_Plex *)dm->data; 5260 5261 PetscFunctionBegin; 5262 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5263 if (section) *section = mesh->coneSection; 5264 PetscFunctionReturn(0); 5265 } 5266 5267 /*@C 5268 DMPlexGetSupportSection - Return a section which describes the layout of support data 5269 5270 Not Collective 5271 5272 Input Parameters: 5273 . dm - The DMPlex object 5274 5275 Output Parameter: 5276 . section - The PetscSection object 5277 5278 Level: developer 5279 5280 .seealso: `DMPlexGetConeSection()` 5281 @*/ 5282 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5283 { 5284 DM_Plex *mesh = (DM_Plex *)dm->data; 5285 5286 PetscFunctionBegin; 5287 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5288 if (section) *section = mesh->supportSection; 5289 PetscFunctionReturn(0); 5290 } 5291 5292 /*@C 5293 DMPlexGetCones - Return cone data 5294 5295 Not Collective 5296 5297 Input Parameters: 5298 . dm - The DMPlex object 5299 5300 Output Parameter: 5301 . cones - The cone for each point 5302 5303 Level: developer 5304 5305 .seealso: `DMPlexGetConeSection()` 5306 @*/ 5307 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5308 { 5309 DM_Plex *mesh = (DM_Plex *)dm->data; 5310 5311 PetscFunctionBegin; 5312 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5313 if (cones) *cones = mesh->cones; 5314 PetscFunctionReturn(0); 5315 } 5316 5317 /*@C 5318 DMPlexGetConeOrientations - Return cone orientation data 5319 5320 Not Collective 5321 5322 Input Parameters: 5323 . dm - The DMPlex object 5324 5325 Output Parameter: 5326 . coneOrientations - The array of cone orientations for all points 5327 5328 Level: developer 5329 5330 Notes: 5331 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5332 5333 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5334 5335 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5336 @*/ 5337 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5338 { 5339 DM_Plex *mesh = (DM_Plex *)dm->data; 5340 5341 PetscFunctionBegin; 5342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5343 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5344 PetscFunctionReturn(0); 5345 } 5346 5347 /******************************** FEM Support **********************************/ 5348 5349 /* 5350 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5351 representing a line in the section. 5352 */ 5353 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5354 { 5355 PetscFunctionBeginHot; 5356 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5357 if (line < 0) { 5358 *k = 0; 5359 *Nc = 0; 5360 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5361 *k = 1; 5362 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5363 /* An order k SEM disc has k-1 dofs on an edge */ 5364 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5365 *k = *k / *Nc + 1; 5366 } 5367 PetscFunctionReturn(0); 5368 } 5369 5370 /*@ 5371 5372 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5373 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5374 section provided (or the section of the DM). 5375 5376 Input Parameters: 5377 + dm - The DM 5378 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5379 - section - The PetscSection to reorder, or NULL for the default section 5380 5381 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5382 degree of the basis. 5383 5384 Example: 5385 A typical interpolated single-quad mesh might order points as 5386 .vb 5387 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5388 5389 v4 -- e6 -- v3 5390 | | 5391 e7 c0 e8 5392 | | 5393 v1 -- e5 -- v2 5394 .ve 5395 5396 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5397 dofs in the order of points, e.g., 5398 .vb 5399 c0 -> [0,1,2,3] 5400 v1 -> [4] 5401 ... 5402 e5 -> [8, 9] 5403 .ve 5404 5405 which corresponds to the dofs 5406 .vb 5407 6 10 11 7 5408 13 2 3 15 5409 12 0 1 14 5410 4 8 9 5 5411 .ve 5412 5413 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5414 .vb 5415 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5416 .ve 5417 5418 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5419 .vb 5420 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5421 .ve 5422 5423 Level: developer 5424 5425 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5426 @*/ 5427 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5428 { 5429 DMLabel label; 5430 PetscInt dim, depth = -1, eStart = -1, Nf; 5431 PetscBool vertexchart; 5432 5433 PetscFunctionBegin; 5434 PetscCall(DMGetDimension(dm, &dim)); 5435 if (dim < 1) PetscFunctionReturn(0); 5436 if (point < 0) { 5437 PetscInt sStart, sEnd; 5438 5439 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5440 point = sEnd - sStart ? sStart : point; 5441 } 5442 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5443 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5444 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5445 if (depth == 1) { 5446 eStart = point; 5447 } else if (depth == dim) { 5448 const PetscInt *cone; 5449 5450 PetscCall(DMPlexGetCone(dm, point, &cone)); 5451 if (dim == 2) eStart = cone[0]; 5452 else if (dim == 3) { 5453 const PetscInt *cone2; 5454 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5455 eStart = cone2[0]; 5456 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5457 } else PetscCheck(depth < 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5458 { /* Determine whether the chart covers all points or just vertices. */ 5459 PetscInt pStart, pEnd, cStart, cEnd; 5460 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5461 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5462 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5463 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5464 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5465 } 5466 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5467 for (PetscInt d = 1; d <= dim; d++) { 5468 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5469 PetscInt *perm; 5470 5471 for (f = 0; f < Nf; ++f) { 5472 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5473 size += PetscPowInt(k + 1, d) * Nc; 5474 } 5475 PetscCall(PetscMalloc1(size, &perm)); 5476 for (f = 0; f < Nf; ++f) { 5477 switch (d) { 5478 case 1: 5479 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5480 /* 5481 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5482 We want [ vtx0; edge of length k-1; vtx1 ] 5483 */ 5484 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5485 for (i = 0; i < k - 1; i++) 5486 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5487 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5488 foffset = offset; 5489 break; 5490 case 2: 5491 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5492 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5493 /* The SEM order is 5494 5495 v_lb, {e_b}, v_rb, 5496 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5497 v_lt, reverse {e_t}, v_rt 5498 */ 5499 { 5500 const PetscInt of = 0; 5501 const PetscInt oeb = of + PetscSqr(k - 1); 5502 const PetscInt oer = oeb + (k - 1); 5503 const PetscInt oet = oer + (k - 1); 5504 const PetscInt oel = oet + (k - 1); 5505 const PetscInt ovlb = oel + (k - 1); 5506 const PetscInt ovrb = ovlb + 1; 5507 const PetscInt ovrt = ovrb + 1; 5508 const PetscInt ovlt = ovrt + 1; 5509 PetscInt o; 5510 5511 /* bottom */ 5512 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5513 for (o = oeb; o < oer; ++o) 5514 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5515 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5516 /* middle */ 5517 for (i = 0; i < k - 1; ++i) { 5518 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5519 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5520 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5521 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5522 } 5523 /* top */ 5524 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5525 for (o = oel - 1; o >= oet; --o) 5526 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5527 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5528 foffset = offset; 5529 } 5530 break; 5531 case 3: 5532 /* The original hex closure is 5533 5534 {c, 5535 f_b, f_t, f_f, f_b, f_r, f_l, 5536 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5537 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5538 */ 5539 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5540 /* The SEM order is 5541 Bottom Slice 5542 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5543 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5544 v_blb, {e_bb}, v_brb, 5545 5546 Middle Slice (j) 5547 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5548 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5549 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5550 5551 Top Slice 5552 v_tlf, {e_tf}, v_trf, 5553 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5554 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5555 */ 5556 { 5557 const PetscInt oc = 0; 5558 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5559 const PetscInt oft = ofb + PetscSqr(k - 1); 5560 const PetscInt off = oft + PetscSqr(k - 1); 5561 const PetscInt ofk = off + PetscSqr(k - 1); 5562 const PetscInt ofr = ofk + PetscSqr(k - 1); 5563 const PetscInt ofl = ofr + PetscSqr(k - 1); 5564 const PetscInt oebl = ofl + PetscSqr(k - 1); 5565 const PetscInt oebb = oebl + (k - 1); 5566 const PetscInt oebr = oebb + (k - 1); 5567 const PetscInt oebf = oebr + (k - 1); 5568 const PetscInt oetf = oebf + (k - 1); 5569 const PetscInt oetr = oetf + (k - 1); 5570 const PetscInt oetb = oetr + (k - 1); 5571 const PetscInt oetl = oetb + (k - 1); 5572 const PetscInt oerf = oetl + (k - 1); 5573 const PetscInt oelf = oerf + (k - 1); 5574 const PetscInt oelb = oelf + (k - 1); 5575 const PetscInt oerb = oelb + (k - 1); 5576 const PetscInt ovblf = oerb + (k - 1); 5577 const PetscInt ovblb = ovblf + 1; 5578 const PetscInt ovbrb = ovblb + 1; 5579 const PetscInt ovbrf = ovbrb + 1; 5580 const PetscInt ovtlf = ovbrf + 1; 5581 const PetscInt ovtrf = ovtlf + 1; 5582 const PetscInt ovtrb = ovtrf + 1; 5583 const PetscInt ovtlb = ovtrb + 1; 5584 PetscInt o, n; 5585 5586 /* Bottom Slice */ 5587 /* bottom */ 5588 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5589 for (o = oetf - 1; o >= oebf; --o) 5590 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5591 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5592 /* middle */ 5593 for (i = 0; i < k - 1; ++i) { 5594 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5595 for (n = 0; n < k - 1; ++n) { 5596 o = ofb + n * (k - 1) + i; 5597 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5598 } 5599 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5600 } 5601 /* top */ 5602 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5603 for (o = oebb; o < oebr; ++o) 5604 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5605 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5606 5607 /* Middle Slice */ 5608 for (j = 0; j < k - 1; ++j) { 5609 /* bottom */ 5610 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5611 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5612 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5613 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5614 /* middle */ 5615 for (i = 0; i < k - 1; ++i) { 5616 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5617 for (n = 0; n < k - 1; ++n) 5618 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5619 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5620 } 5621 /* top */ 5622 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5623 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5624 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5625 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5626 } 5627 5628 /* Top Slice */ 5629 /* bottom */ 5630 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5631 for (o = oetf; o < oetr; ++o) 5632 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5633 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5634 /* middle */ 5635 for (i = 0; i < k - 1; ++i) { 5636 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5637 for (n = 0; n < k - 1; ++n) 5638 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5639 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5640 } 5641 /* top */ 5642 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5643 for (o = oetl - 1; o >= oetb; --o) 5644 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5645 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5646 5647 foffset = offset; 5648 } 5649 break; 5650 default: 5651 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5652 } 5653 } 5654 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5655 /* Check permutation */ 5656 { 5657 PetscInt *check; 5658 5659 PetscCall(PetscMalloc1(size, &check)); 5660 for (i = 0; i < size; ++i) { 5661 check[i] = -1; 5662 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5663 } 5664 for (i = 0; i < size; ++i) check[perm[i]] = i; 5665 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5666 PetscCall(PetscFree(check)); 5667 } 5668 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5669 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5670 PetscInt *loc_perm; 5671 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5672 for (PetscInt i = 0; i < size; i++) { 5673 loc_perm[i] = perm[i]; 5674 loc_perm[size + i] = size + perm[i]; 5675 } 5676 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5677 } 5678 } 5679 PetscFunctionReturn(0); 5680 } 5681 5682 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5683 { 5684 PetscDS prob; 5685 PetscInt depth, Nf, h; 5686 DMLabel label; 5687 5688 PetscFunctionBeginHot; 5689 PetscCall(DMGetDS(dm, &prob)); 5690 Nf = prob->Nf; 5691 label = dm->depthLabel; 5692 *dspace = NULL; 5693 if (field < Nf) { 5694 PetscObject disc = prob->disc[field]; 5695 5696 if (disc->classid == PETSCFE_CLASSID) { 5697 PetscDualSpace dsp; 5698 5699 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5700 PetscCall(DMLabelGetNumValues(label, &depth)); 5701 PetscCall(DMLabelGetValue(label, point, &h)); 5702 h = depth - 1 - h; 5703 if (h) { 5704 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5705 } else { 5706 *dspace = dsp; 5707 } 5708 } 5709 } 5710 PetscFunctionReturn(0); 5711 } 5712 5713 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5714 { 5715 PetscScalar *array; 5716 const PetscScalar *vArray; 5717 const PetscInt *cone, *coneO; 5718 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5719 5720 PetscFunctionBeginHot; 5721 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5722 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5723 PetscCall(DMPlexGetCone(dm, point, &cone)); 5724 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5725 if (!values || !*values) { 5726 if ((point >= pStart) && (point < pEnd)) { 5727 PetscInt dof; 5728 5729 PetscCall(PetscSectionGetDof(section, point, &dof)); 5730 size += dof; 5731 } 5732 for (p = 0; p < numPoints; ++p) { 5733 const PetscInt cp = cone[p]; 5734 PetscInt dof; 5735 5736 if ((cp < pStart) || (cp >= pEnd)) continue; 5737 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5738 size += dof; 5739 } 5740 if (!values) { 5741 if (csize) *csize = size; 5742 PetscFunctionReturn(0); 5743 } 5744 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5745 } else { 5746 array = *values; 5747 } 5748 size = 0; 5749 PetscCall(VecGetArrayRead(v, &vArray)); 5750 if ((point >= pStart) && (point < pEnd)) { 5751 PetscInt dof, off, d; 5752 const PetscScalar *varr; 5753 5754 PetscCall(PetscSectionGetDof(section, point, &dof)); 5755 PetscCall(PetscSectionGetOffset(section, point, &off)); 5756 varr = &vArray[off]; 5757 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5758 size += dof; 5759 } 5760 for (p = 0; p < numPoints; ++p) { 5761 const PetscInt cp = cone[p]; 5762 PetscInt o = coneO[p]; 5763 PetscInt dof, off, d; 5764 const PetscScalar *varr; 5765 5766 if ((cp < pStart) || (cp >= pEnd)) continue; 5767 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5768 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5769 varr = &vArray[off]; 5770 if (o >= 0) { 5771 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5772 } else { 5773 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5774 } 5775 size += dof; 5776 } 5777 PetscCall(VecRestoreArrayRead(v, &vArray)); 5778 if (!*values) { 5779 if (csize) *csize = size; 5780 *values = array; 5781 } else { 5782 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5783 *csize = size; 5784 } 5785 PetscFunctionReturn(0); 5786 } 5787 5788 /* Compress out points not in the section */ 5789 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5790 { 5791 const PetscInt np = *numPoints; 5792 PetscInt pStart, pEnd, p, q; 5793 5794 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5795 for (p = 0, q = 0; p < np; ++p) { 5796 const PetscInt r = points[p * 2]; 5797 if ((r >= pStart) && (r < pEnd)) { 5798 points[q * 2] = r; 5799 points[q * 2 + 1] = points[p * 2 + 1]; 5800 ++q; 5801 } 5802 } 5803 *numPoints = q; 5804 return 0; 5805 } 5806 5807 /* Compressed closure does not apply closure permutation */ 5808 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5809 { 5810 const PetscInt *cla = NULL; 5811 PetscInt np, *pts = NULL; 5812 5813 PetscFunctionBeginHot; 5814 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5815 if (*clPoints) { 5816 PetscInt dof, off; 5817 5818 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5819 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5820 PetscCall(ISGetIndices(*clPoints, &cla)); 5821 np = dof / 2; 5822 pts = (PetscInt *)&cla[off]; 5823 } else { 5824 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5825 PetscCall(CompressPoints_Private(section, &np, pts)); 5826 } 5827 *numPoints = np; 5828 *points = pts; 5829 *clp = cla; 5830 PetscFunctionReturn(0); 5831 } 5832 5833 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5834 { 5835 PetscFunctionBeginHot; 5836 if (!*clPoints) { 5837 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5838 } else { 5839 PetscCall(ISRestoreIndices(*clPoints, clp)); 5840 } 5841 *numPoints = 0; 5842 *points = NULL; 5843 *clSec = NULL; 5844 *clPoints = NULL; 5845 *clp = NULL; 5846 PetscFunctionReturn(0); 5847 } 5848 5849 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5850 { 5851 PetscInt offset = 0, p; 5852 const PetscInt **perms = NULL; 5853 const PetscScalar **flips = NULL; 5854 5855 PetscFunctionBeginHot; 5856 *size = 0; 5857 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5858 for (p = 0; p < numPoints; p++) { 5859 const PetscInt point = points[2 * p]; 5860 const PetscInt *perm = perms ? perms[p] : NULL; 5861 const PetscScalar *flip = flips ? flips[p] : NULL; 5862 PetscInt dof, off, d; 5863 const PetscScalar *varr; 5864 5865 PetscCall(PetscSectionGetDof(section, point, &dof)); 5866 PetscCall(PetscSectionGetOffset(section, point, &off)); 5867 varr = &vArray[off]; 5868 if (clperm) { 5869 if (perm) { 5870 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5871 } else { 5872 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5873 } 5874 if (flip) { 5875 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5876 } 5877 } else { 5878 if (perm) { 5879 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5880 } else { 5881 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5882 } 5883 if (flip) { 5884 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5885 } 5886 } 5887 offset += dof; 5888 } 5889 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5890 *size = offset; 5891 PetscFunctionReturn(0); 5892 } 5893 5894 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[]) 5895 { 5896 PetscInt offset = 0, f; 5897 5898 PetscFunctionBeginHot; 5899 *size = 0; 5900 for (f = 0; f < numFields; ++f) { 5901 PetscInt p; 5902 const PetscInt **perms = NULL; 5903 const PetscScalar **flips = NULL; 5904 5905 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5906 for (p = 0; p < numPoints; p++) { 5907 const PetscInt point = points[2 * p]; 5908 PetscInt fdof, foff, b; 5909 const PetscScalar *varr; 5910 const PetscInt *perm = perms ? perms[p] : NULL; 5911 const PetscScalar *flip = flips ? flips[p] : NULL; 5912 5913 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5914 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5915 varr = &vArray[foff]; 5916 if (clperm) { 5917 if (perm) { 5918 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5919 } else { 5920 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5921 } 5922 if (flip) { 5923 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5924 } 5925 } else { 5926 if (perm) { 5927 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5928 } else { 5929 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5930 } 5931 if (flip) { 5932 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5933 } 5934 } 5935 offset += fdof; 5936 } 5937 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5938 } 5939 *size = offset; 5940 PetscFunctionReturn(0); 5941 } 5942 5943 /*@C 5944 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5945 5946 Not collective 5947 5948 Input Parameters: 5949 + dm - The DM 5950 . section - The section describing the layout in v, or NULL to use the default section 5951 . v - The local vector 5952 - point - The point in the DM 5953 5954 Input/Output Parameters: 5955 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5956 - values - An array to use for the values, or NULL to have it allocated automatically; 5957 if the user provided NULL, it is a borrowed array and should not be freed 5958 5959 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5960 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5961 $ assembly function, and a user may already have allocated storage for this operation. 5962 $ 5963 $ A typical use could be 5964 $ 5965 $ values = NULL; 5966 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5967 $ for (cl = 0; cl < clSize; ++cl) { 5968 $ <Compute on closure> 5969 $ } 5970 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5971 $ 5972 $ or 5973 $ 5974 $ PetscMalloc1(clMaxSize, &values); 5975 $ for (p = pStart; p < pEnd; ++p) { 5976 $ clSize = clMaxSize; 5977 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5978 $ for (cl = 0; cl < clSize; ++cl) { 5979 $ <Compute on closure> 5980 $ } 5981 $ } 5982 $ PetscFree(values); 5983 5984 Fortran Notes: 5985 Since it returns an array, this routine is only available in Fortran 90, and you must 5986 include petsc.h90 in your code. 5987 5988 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5989 5990 Level: intermediate 5991 5992 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5993 @*/ 5994 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5995 { 5996 PetscSection clSection; 5997 IS clPoints; 5998 PetscInt *points = NULL; 5999 const PetscInt *clp, *perm; 6000 PetscInt depth, numFields, numPoints, asize; 6001 6002 PetscFunctionBeginHot; 6003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6004 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6005 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6006 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6007 PetscCall(DMPlexGetDepth(dm, &depth)); 6008 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6009 if (depth == 1 && numFields < 2) { 6010 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6011 PetscFunctionReturn(0); 6012 } 6013 /* Get points */ 6014 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6015 /* Get sizes */ 6016 asize = 0; 6017 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6018 PetscInt dof; 6019 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6020 asize += dof; 6021 } 6022 if (values) { 6023 const PetscScalar *vArray; 6024 PetscInt size; 6025 6026 if (*values) { 6027 PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 6028 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6029 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6030 PetscCall(VecGetArrayRead(v, &vArray)); 6031 /* Get values */ 6032 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6033 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6034 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6035 /* Cleanup array */ 6036 PetscCall(VecRestoreArrayRead(v, &vArray)); 6037 } 6038 if (csize) *csize = asize; 6039 /* Cleanup points */ 6040 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6041 PetscFunctionReturn(0); 6042 } 6043 6044 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6045 { 6046 DMLabel depthLabel; 6047 PetscSection clSection; 6048 IS clPoints; 6049 PetscScalar *array; 6050 const PetscScalar *vArray; 6051 PetscInt *points = NULL; 6052 const PetscInt *clp, *perm = NULL; 6053 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6054 6055 PetscFunctionBeginHot; 6056 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6057 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6058 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6059 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6060 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6061 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6062 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6063 if (mdepth == 1 && numFields < 2) { 6064 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6065 PetscFunctionReturn(0); 6066 } 6067 /* Get points */ 6068 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6069 for (clsize = 0, p = 0; p < Np; p++) { 6070 PetscInt dof; 6071 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6072 clsize += dof; 6073 } 6074 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6075 /* Filter points */ 6076 for (p = 0; p < numPoints * 2; p += 2) { 6077 PetscInt dep; 6078 6079 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6080 if (dep != depth) continue; 6081 points[Np * 2 + 0] = points[p]; 6082 points[Np * 2 + 1] = points[p + 1]; 6083 ++Np; 6084 } 6085 /* Get array */ 6086 if (!values || !*values) { 6087 PetscInt asize = 0, dof; 6088 6089 for (p = 0; p < Np * 2; p += 2) { 6090 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6091 asize += dof; 6092 } 6093 if (!values) { 6094 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6095 if (csize) *csize = asize; 6096 PetscFunctionReturn(0); 6097 } 6098 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6099 } else { 6100 array = *values; 6101 } 6102 PetscCall(VecGetArrayRead(v, &vArray)); 6103 /* Get values */ 6104 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6105 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6106 /* Cleanup points */ 6107 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6108 /* Cleanup array */ 6109 PetscCall(VecRestoreArrayRead(v, &vArray)); 6110 if (!*values) { 6111 if (csize) *csize = size; 6112 *values = array; 6113 } else { 6114 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6115 *csize = size; 6116 } 6117 PetscFunctionReturn(0); 6118 } 6119 6120 /*@C 6121 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6122 6123 Not collective 6124 6125 Input Parameters: 6126 + dm - The DM 6127 . section - The section describing the layout in v, or NULL to use the default section 6128 . v - The local vector 6129 . point - The point in the DM 6130 . csize - The number of values in the closure, or NULL 6131 - values - The array of values, which is a borrowed array and should not be freed 6132 6133 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 6134 6135 Fortran Notes: 6136 Since it returns an array, this routine is only available in Fortran 90, and you must 6137 include petsc.h90 in your code. 6138 6139 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 6140 6141 Level: intermediate 6142 6143 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6144 @*/ 6145 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6146 { 6147 PetscInt size = 0; 6148 6149 PetscFunctionBegin; 6150 /* Should work without recalculating size */ 6151 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6152 *values = NULL; 6153 PetscFunctionReturn(0); 6154 } 6155 6156 static inline void add(PetscScalar *x, PetscScalar y) 6157 { 6158 *x += y; 6159 } 6160 static inline void insert(PetscScalar *x, PetscScalar y) 6161 { 6162 *x = y; 6163 } 6164 6165 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[]) 6166 { 6167 PetscInt cdof; /* The number of constraints on this point */ 6168 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6169 PetscScalar *a; 6170 PetscInt off, cind = 0, k; 6171 6172 PetscFunctionBegin; 6173 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6174 PetscCall(PetscSectionGetOffset(section, point, &off)); 6175 a = &array[off]; 6176 if (!cdof || setBC) { 6177 if (clperm) { 6178 if (perm) { 6179 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6180 } else { 6181 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6182 } 6183 } else { 6184 if (perm) { 6185 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6186 } else { 6187 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6188 } 6189 } 6190 } else { 6191 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6192 if (clperm) { 6193 if (perm) { 6194 for (k = 0; k < dof; ++k) { 6195 if ((cind < cdof) && (k == cdofs[cind])) { 6196 ++cind; 6197 continue; 6198 } 6199 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6200 } 6201 } else { 6202 for (k = 0; k < dof; ++k) { 6203 if ((cind < cdof) && (k == cdofs[cind])) { 6204 ++cind; 6205 continue; 6206 } 6207 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6208 } 6209 } 6210 } else { 6211 if (perm) { 6212 for (k = 0; k < dof; ++k) { 6213 if ((cind < cdof) && (k == cdofs[cind])) { 6214 ++cind; 6215 continue; 6216 } 6217 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6218 } 6219 } else { 6220 for (k = 0; k < dof; ++k) { 6221 if ((cind < cdof) && (k == cdofs[cind])) { 6222 ++cind; 6223 continue; 6224 } 6225 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6226 } 6227 } 6228 } 6229 } 6230 PetscFunctionReturn(0); 6231 } 6232 6233 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[]) 6234 { 6235 PetscInt cdof; /* The number of constraints on this point */ 6236 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6237 PetscScalar *a; 6238 PetscInt off, cind = 0, k; 6239 6240 PetscFunctionBegin; 6241 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6242 PetscCall(PetscSectionGetOffset(section, point, &off)); 6243 a = &array[off]; 6244 if (cdof) { 6245 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6246 if (clperm) { 6247 if (perm) { 6248 for (k = 0; k < dof; ++k) { 6249 if ((cind < cdof) && (k == cdofs[cind])) { 6250 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6251 cind++; 6252 } 6253 } 6254 } else { 6255 for (k = 0; k < dof; ++k) { 6256 if ((cind < cdof) && (k == cdofs[cind])) { 6257 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6258 cind++; 6259 } 6260 } 6261 } 6262 } else { 6263 if (perm) { 6264 for (k = 0; k < dof; ++k) { 6265 if ((cind < cdof) && (k == cdofs[cind])) { 6266 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6267 cind++; 6268 } 6269 } 6270 } else { 6271 for (k = 0; k < dof; ++k) { 6272 if ((cind < cdof) && (k == cdofs[cind])) { 6273 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6274 cind++; 6275 } 6276 } 6277 } 6278 } 6279 } 6280 PetscFunctionReturn(0); 6281 } 6282 6283 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[]) 6284 { 6285 PetscScalar *a; 6286 PetscInt fdof, foff, fcdof, foffset = *offset; 6287 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6288 PetscInt cind = 0, b; 6289 6290 PetscFunctionBegin; 6291 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6292 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6293 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6294 a = &array[foff]; 6295 if (!fcdof || setBC) { 6296 if (clperm) { 6297 if (perm) { 6298 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6299 } else { 6300 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6301 } 6302 } else { 6303 if (perm) { 6304 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6305 } else { 6306 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6307 } 6308 } 6309 } else { 6310 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6311 if (clperm) { 6312 if (perm) { 6313 for (b = 0; b < fdof; b++) { 6314 if ((cind < fcdof) && (b == fcdofs[cind])) { 6315 ++cind; 6316 continue; 6317 } 6318 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6319 } 6320 } else { 6321 for (b = 0; b < fdof; b++) { 6322 if ((cind < fcdof) && (b == fcdofs[cind])) { 6323 ++cind; 6324 continue; 6325 } 6326 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6327 } 6328 } 6329 } else { 6330 if (perm) { 6331 for (b = 0; b < fdof; b++) { 6332 if ((cind < fcdof) && (b == fcdofs[cind])) { 6333 ++cind; 6334 continue; 6335 } 6336 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6337 } 6338 } else { 6339 for (b = 0; b < fdof; b++) { 6340 if ((cind < fcdof) && (b == fcdofs[cind])) { 6341 ++cind; 6342 continue; 6343 } 6344 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6345 } 6346 } 6347 } 6348 } 6349 *offset += fdof; 6350 PetscFunctionReturn(0); 6351 } 6352 6353 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[]) 6354 { 6355 PetscScalar *a; 6356 PetscInt fdof, foff, fcdof, foffset = *offset; 6357 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6358 PetscInt Nc, cind = 0, ncind = 0, b; 6359 PetscBool ncSet, fcSet; 6360 6361 PetscFunctionBegin; 6362 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6363 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6364 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6365 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6366 a = &array[foff]; 6367 if (fcdof) { 6368 /* We just override fcdof and fcdofs with Ncc and comps */ 6369 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6370 if (clperm) { 6371 if (perm) { 6372 if (comps) { 6373 for (b = 0; b < fdof; b++) { 6374 ncSet = fcSet = PETSC_FALSE; 6375 if (b % Nc == comps[ncind]) { 6376 ncind = (ncind + 1) % Ncc; 6377 ncSet = PETSC_TRUE; 6378 } 6379 if ((cind < fcdof) && (b == fcdofs[cind])) { 6380 ++cind; 6381 fcSet = PETSC_TRUE; 6382 } 6383 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6384 } 6385 } else { 6386 for (b = 0; b < fdof; b++) { 6387 if ((cind < fcdof) && (b == fcdofs[cind])) { 6388 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6389 ++cind; 6390 } 6391 } 6392 } 6393 } else { 6394 if (comps) { 6395 for (b = 0; b < fdof; b++) { 6396 ncSet = fcSet = PETSC_FALSE; 6397 if (b % Nc == comps[ncind]) { 6398 ncind = (ncind + 1) % Ncc; 6399 ncSet = PETSC_TRUE; 6400 } 6401 if ((cind < fcdof) && (b == fcdofs[cind])) { 6402 ++cind; 6403 fcSet = PETSC_TRUE; 6404 } 6405 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6406 } 6407 } else { 6408 for (b = 0; b < fdof; b++) { 6409 if ((cind < fcdof) && (b == fcdofs[cind])) { 6410 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6411 ++cind; 6412 } 6413 } 6414 } 6415 } 6416 } else { 6417 if (perm) { 6418 if (comps) { 6419 for (b = 0; b < fdof; b++) { 6420 ncSet = fcSet = PETSC_FALSE; 6421 if (b % Nc == comps[ncind]) { 6422 ncind = (ncind + 1) % Ncc; 6423 ncSet = PETSC_TRUE; 6424 } 6425 if ((cind < fcdof) && (b == fcdofs[cind])) { 6426 ++cind; 6427 fcSet = PETSC_TRUE; 6428 } 6429 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6430 } 6431 } else { 6432 for (b = 0; b < fdof; b++) { 6433 if ((cind < fcdof) && (b == fcdofs[cind])) { 6434 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6435 ++cind; 6436 } 6437 } 6438 } 6439 } else { 6440 if (comps) { 6441 for (b = 0; b < fdof; b++) { 6442 ncSet = fcSet = PETSC_FALSE; 6443 if (b % Nc == comps[ncind]) { 6444 ncind = (ncind + 1) % Ncc; 6445 ncSet = PETSC_TRUE; 6446 } 6447 if ((cind < fcdof) && (b == fcdofs[cind])) { 6448 ++cind; 6449 fcSet = PETSC_TRUE; 6450 } 6451 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6452 } 6453 } else { 6454 for (b = 0; b < fdof; b++) { 6455 if ((cind < fcdof) && (b == fcdofs[cind])) { 6456 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6457 ++cind; 6458 } 6459 } 6460 } 6461 } 6462 } 6463 } 6464 *offset += fdof; 6465 PetscFunctionReturn(0); 6466 } 6467 6468 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6469 { 6470 PetscScalar *array; 6471 const PetscInt *cone, *coneO; 6472 PetscInt pStart, pEnd, p, numPoints, off, dof; 6473 6474 PetscFunctionBeginHot; 6475 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6476 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6477 PetscCall(DMPlexGetCone(dm, point, &cone)); 6478 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6479 PetscCall(VecGetArray(v, &array)); 6480 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6481 const PetscInt cp = !p ? point : cone[p - 1]; 6482 const PetscInt o = !p ? 0 : coneO[p - 1]; 6483 6484 if ((cp < pStart) || (cp >= pEnd)) { 6485 dof = 0; 6486 continue; 6487 } 6488 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6489 /* ADD_VALUES */ 6490 { 6491 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6492 PetscScalar *a; 6493 PetscInt cdof, coff, cind = 0, k; 6494 6495 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6496 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6497 a = &array[coff]; 6498 if (!cdof) { 6499 if (o >= 0) { 6500 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6501 } else { 6502 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6503 } 6504 } else { 6505 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6506 if (o >= 0) { 6507 for (k = 0; k < dof; ++k) { 6508 if ((cind < cdof) && (k == cdofs[cind])) { 6509 ++cind; 6510 continue; 6511 } 6512 a[k] += values[off + k]; 6513 } 6514 } else { 6515 for (k = 0; k < dof; ++k) { 6516 if ((cind < cdof) && (k == cdofs[cind])) { 6517 ++cind; 6518 continue; 6519 } 6520 a[k] += values[off + dof - k - 1]; 6521 } 6522 } 6523 } 6524 } 6525 } 6526 PetscCall(VecRestoreArray(v, &array)); 6527 PetscFunctionReturn(0); 6528 } 6529 6530 /*@C 6531 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6532 6533 Not collective 6534 6535 Input Parameters: 6536 + dm - The DM 6537 . section - The section describing the layout in v, or NULL to use the default section 6538 . v - The local vector 6539 . point - The point in the DM 6540 . values - The array of values 6541 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6542 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6543 6544 Fortran Notes: 6545 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6546 6547 Level: intermediate 6548 6549 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6550 @*/ 6551 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6552 { 6553 PetscSection clSection; 6554 IS clPoints; 6555 PetscScalar *array; 6556 PetscInt *points = NULL; 6557 const PetscInt *clp, *clperm = NULL; 6558 PetscInt depth, numFields, numPoints, p, clsize; 6559 6560 PetscFunctionBeginHot; 6561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6562 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6563 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6564 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6565 PetscCall(DMPlexGetDepth(dm, &depth)); 6566 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6567 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6568 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6569 PetscFunctionReturn(0); 6570 } 6571 /* Get points */ 6572 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6573 for (clsize = 0, p = 0; p < numPoints; p++) { 6574 PetscInt dof; 6575 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6576 clsize += dof; 6577 } 6578 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6579 /* Get array */ 6580 PetscCall(VecGetArray(v, &array)); 6581 /* Get values */ 6582 if (numFields > 0) { 6583 PetscInt offset = 0, f; 6584 for (f = 0; f < numFields; ++f) { 6585 const PetscInt **perms = NULL; 6586 const PetscScalar **flips = NULL; 6587 6588 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6589 switch (mode) { 6590 case INSERT_VALUES: 6591 for (p = 0; p < numPoints; p++) { 6592 const PetscInt point = points[2 * p]; 6593 const PetscInt *perm = perms ? perms[p] : NULL; 6594 const PetscScalar *flip = flips ? flips[p] : NULL; 6595 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6596 } 6597 break; 6598 case INSERT_ALL_VALUES: 6599 for (p = 0; p < numPoints; p++) { 6600 const PetscInt point = points[2 * p]; 6601 const PetscInt *perm = perms ? perms[p] : NULL; 6602 const PetscScalar *flip = flips ? flips[p] : NULL; 6603 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6604 } 6605 break; 6606 case INSERT_BC_VALUES: 6607 for (p = 0; p < numPoints; p++) { 6608 const PetscInt point = points[2 * p]; 6609 const PetscInt *perm = perms ? perms[p] : NULL; 6610 const PetscScalar *flip = flips ? flips[p] : NULL; 6611 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6612 } 6613 break; 6614 case ADD_VALUES: 6615 for (p = 0; p < numPoints; p++) { 6616 const PetscInt point = points[2 * p]; 6617 const PetscInt *perm = perms ? perms[p] : NULL; 6618 const PetscScalar *flip = flips ? flips[p] : NULL; 6619 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6620 } 6621 break; 6622 case ADD_ALL_VALUES: 6623 for (p = 0; p < numPoints; p++) { 6624 const PetscInt point = points[2 * p]; 6625 const PetscInt *perm = perms ? perms[p] : NULL; 6626 const PetscScalar *flip = flips ? flips[p] : NULL; 6627 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6628 } 6629 break; 6630 case ADD_BC_VALUES: 6631 for (p = 0; p < numPoints; p++) { 6632 const PetscInt point = points[2 * p]; 6633 const PetscInt *perm = perms ? perms[p] : NULL; 6634 const PetscScalar *flip = flips ? flips[p] : NULL; 6635 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6636 } 6637 break; 6638 default: 6639 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6640 } 6641 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6642 } 6643 } else { 6644 PetscInt dof, off; 6645 const PetscInt **perms = NULL; 6646 const PetscScalar **flips = NULL; 6647 6648 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6649 switch (mode) { 6650 case INSERT_VALUES: 6651 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6652 const PetscInt point = points[2 * p]; 6653 const PetscInt *perm = perms ? perms[p] : NULL; 6654 const PetscScalar *flip = flips ? flips[p] : NULL; 6655 PetscCall(PetscSectionGetDof(section, point, &dof)); 6656 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6657 } 6658 break; 6659 case INSERT_ALL_VALUES: 6660 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6661 const PetscInt point = points[2 * p]; 6662 const PetscInt *perm = perms ? perms[p] : NULL; 6663 const PetscScalar *flip = flips ? flips[p] : NULL; 6664 PetscCall(PetscSectionGetDof(section, point, &dof)); 6665 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6666 } 6667 break; 6668 case INSERT_BC_VALUES: 6669 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6670 const PetscInt point = points[2 * p]; 6671 const PetscInt *perm = perms ? perms[p] : NULL; 6672 const PetscScalar *flip = flips ? flips[p] : NULL; 6673 PetscCall(PetscSectionGetDof(section, point, &dof)); 6674 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6675 } 6676 break; 6677 case ADD_VALUES: 6678 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6679 const PetscInt point = points[2 * p]; 6680 const PetscInt *perm = perms ? perms[p] : NULL; 6681 const PetscScalar *flip = flips ? flips[p] : NULL; 6682 PetscCall(PetscSectionGetDof(section, point, &dof)); 6683 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6684 } 6685 break; 6686 case ADD_ALL_VALUES: 6687 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6688 const PetscInt point = points[2 * p]; 6689 const PetscInt *perm = perms ? perms[p] : NULL; 6690 const PetscScalar *flip = flips ? flips[p] : NULL; 6691 PetscCall(PetscSectionGetDof(section, point, &dof)); 6692 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6693 } 6694 break; 6695 case ADD_BC_VALUES: 6696 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6697 const PetscInt point = points[2 * p]; 6698 const PetscInt *perm = perms ? perms[p] : NULL; 6699 const PetscScalar *flip = flips ? flips[p] : NULL; 6700 PetscCall(PetscSectionGetDof(section, point, &dof)); 6701 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6702 } 6703 break; 6704 default: 6705 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6706 } 6707 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6708 } 6709 /* Cleanup points */ 6710 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6711 /* Cleanup array */ 6712 PetscCall(VecRestoreArray(v, &array)); 6713 PetscFunctionReturn(0); 6714 } 6715 6716 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6717 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6718 { 6719 PetscFunctionBegin; 6720 *contains = PETSC_TRUE; 6721 if (label) { 6722 PetscInt fdof; 6723 6724 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6725 if (!*contains) { 6726 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6727 *offset += fdof; 6728 PetscFunctionReturn(0); 6729 } 6730 } 6731 PetscFunctionReturn(0); 6732 } 6733 6734 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6735 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt labelId, const PetscScalar values[], InsertMode mode) 6736 { 6737 PetscSection clSection; 6738 IS clPoints; 6739 PetscScalar *array; 6740 PetscInt *points = NULL; 6741 const PetscInt *clp; 6742 PetscInt numFields, numPoints, p; 6743 PetscInt offset = 0, f; 6744 6745 PetscFunctionBeginHot; 6746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6747 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6748 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6749 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6750 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6751 /* Get points */ 6752 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6753 /* Get array */ 6754 PetscCall(VecGetArray(v, &array)); 6755 /* Get values */ 6756 for (f = 0; f < numFields; ++f) { 6757 const PetscInt **perms = NULL; 6758 const PetscScalar **flips = NULL; 6759 PetscBool contains; 6760 6761 if (!fieldActive[f]) { 6762 for (p = 0; p < numPoints * 2; p += 2) { 6763 PetscInt fdof; 6764 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6765 offset += fdof; 6766 } 6767 continue; 6768 } 6769 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6770 switch (mode) { 6771 case INSERT_VALUES: 6772 for (p = 0; p < numPoints; p++) { 6773 const PetscInt point = points[2 * p]; 6774 const PetscInt *perm = perms ? perms[p] : NULL; 6775 const PetscScalar *flip = flips ? flips[p] : NULL; 6776 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6777 if (!contains) continue; 6778 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6779 } 6780 break; 6781 case INSERT_ALL_VALUES: 6782 for (p = 0; p < numPoints; p++) { 6783 const PetscInt point = points[2 * p]; 6784 const PetscInt *perm = perms ? perms[p] : NULL; 6785 const PetscScalar *flip = flips ? flips[p] : NULL; 6786 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6787 if (!contains) continue; 6788 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6789 } 6790 break; 6791 case INSERT_BC_VALUES: 6792 for (p = 0; p < numPoints; p++) { 6793 const PetscInt point = points[2 * p]; 6794 const PetscInt *perm = perms ? perms[p] : NULL; 6795 const PetscScalar *flip = flips ? flips[p] : NULL; 6796 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6797 if (!contains) continue; 6798 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6799 } 6800 break; 6801 case ADD_VALUES: 6802 for (p = 0; p < numPoints; p++) { 6803 const PetscInt point = points[2 * p]; 6804 const PetscInt *perm = perms ? perms[p] : NULL; 6805 const PetscScalar *flip = flips ? flips[p] : NULL; 6806 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6807 if (!contains) continue; 6808 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6809 } 6810 break; 6811 case ADD_ALL_VALUES: 6812 for (p = 0; p < numPoints; p++) { 6813 const PetscInt point = points[2 * p]; 6814 const PetscInt *perm = perms ? perms[p] : NULL; 6815 const PetscScalar *flip = flips ? flips[p] : NULL; 6816 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6817 if (!contains) continue; 6818 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6819 } 6820 break; 6821 default: 6822 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6823 } 6824 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6825 } 6826 /* Cleanup points */ 6827 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6828 /* Cleanup array */ 6829 PetscCall(VecRestoreArray(v, &array)); 6830 PetscFunctionReturn(0); 6831 } 6832 6833 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6834 { 6835 PetscMPIInt rank; 6836 PetscInt i, j; 6837 6838 PetscFunctionBegin; 6839 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6840 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6841 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6842 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6843 numCIndices = numCIndices ? numCIndices : numRIndices; 6844 if (!values) PetscFunctionReturn(0); 6845 for (i = 0; i < numRIndices; i++) { 6846 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6847 for (j = 0; j < numCIndices; j++) { 6848 #if defined(PETSC_USE_COMPLEX) 6849 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6850 #else 6851 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6852 #endif 6853 } 6854 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6855 } 6856 PetscFunctionReturn(0); 6857 } 6858 6859 /* 6860 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6861 6862 Input Parameters: 6863 + section - The section for this data layout 6864 . islocal - Is the section (and thus indices being requested) local or global? 6865 . point - The point contributing dofs with these indices 6866 . off - The global offset of this point 6867 . loff - The local offset of each field 6868 . setBC - The flag determining whether to include indices of boundary values 6869 . perm - A permutation of the dofs on this point, or NULL 6870 - indperm - A permutation of the entire indices array, or NULL 6871 6872 Output Parameter: 6873 . indices - Indices for dofs on this point 6874 6875 Level: developer 6876 6877 Note: The indices could be local or global, depending on the value of 'off'. 6878 */ 6879 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6880 { 6881 PetscInt dof; /* The number of unknowns on this point */ 6882 PetscInt cdof; /* The number of constraints on this point */ 6883 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6884 PetscInt cind = 0, k; 6885 6886 PetscFunctionBegin; 6887 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6888 PetscCall(PetscSectionGetDof(section, point, &dof)); 6889 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6890 if (!cdof || setBC) { 6891 for (k = 0; k < dof; ++k) { 6892 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6893 const PetscInt ind = indperm ? indperm[preind] : preind; 6894 6895 indices[ind] = off + k; 6896 } 6897 } else { 6898 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6899 for (k = 0; k < dof; ++k) { 6900 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6901 const PetscInt ind = indperm ? indperm[preind] : preind; 6902 6903 if ((cind < cdof) && (k == cdofs[cind])) { 6904 /* Insert check for returning constrained indices */ 6905 indices[ind] = -(off + k + 1); 6906 ++cind; 6907 } else { 6908 indices[ind] = off + k - (islocal ? 0 : cind); 6909 } 6910 } 6911 } 6912 *loff += dof; 6913 PetscFunctionReturn(0); 6914 } 6915 6916 /* 6917 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6918 6919 Input Parameters: 6920 + section - a section (global or local) 6921 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6922 . point - point within section 6923 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6924 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6925 . setBC - identify constrained (boundary condition) points via involution. 6926 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6927 . permsoff - offset 6928 - indperm - index permutation 6929 6930 Output Parameter: 6931 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6932 . indices - array to hold indices (as defined by section) of each dof associated with point 6933 6934 Notes: 6935 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6936 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6937 in the local vector. 6938 6939 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6940 significant). It is invalid to call with a global section and setBC=true. 6941 6942 Developer Note: 6943 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6944 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6945 offset could be obtained from the section instead of passing it explicitly as we do now. 6946 6947 Example: 6948 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6949 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6950 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6951 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. 6952 6953 Level: developer 6954 */ 6955 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[]) 6956 { 6957 PetscInt numFields, foff, f; 6958 6959 PetscFunctionBegin; 6960 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6961 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6962 for (f = 0, foff = 0; f < numFields; ++f) { 6963 PetscInt fdof, cfdof; 6964 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6965 PetscInt cind = 0, b; 6966 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6967 6968 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6969 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6970 if (!cfdof || setBC) { 6971 for (b = 0; b < fdof; ++b) { 6972 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6973 const PetscInt ind = indperm ? indperm[preind] : preind; 6974 6975 indices[ind] = off + foff + b; 6976 } 6977 } else { 6978 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6979 for (b = 0; b < fdof; ++b) { 6980 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6981 const PetscInt ind = indperm ? indperm[preind] : preind; 6982 6983 if ((cind < cfdof) && (b == fcdofs[cind])) { 6984 indices[ind] = -(off + foff + b + 1); 6985 ++cind; 6986 } else { 6987 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6988 } 6989 } 6990 } 6991 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6992 foffs[f] += fdof; 6993 } 6994 PetscFunctionReturn(0); 6995 } 6996 6997 /* 6998 This version believes the globalSection offsets for each field, rather than just the point offset 6999 7000 . foffs - The offset into 'indices' for each field, since it is segregated by field 7001 7002 Notes: 7003 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7004 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7005 */ 7006 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7007 { 7008 PetscInt numFields, foff, f; 7009 7010 PetscFunctionBegin; 7011 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7012 for (f = 0; f < numFields; ++f) { 7013 PetscInt fdof, cfdof; 7014 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7015 PetscInt cind = 0, b; 7016 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7017 7018 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7019 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7020 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7021 if (!cfdof) { 7022 for (b = 0; b < fdof; ++b) { 7023 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7024 const PetscInt ind = indperm ? indperm[preind] : preind; 7025 7026 indices[ind] = foff + b; 7027 } 7028 } else { 7029 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7030 for (b = 0; b < fdof; ++b) { 7031 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7032 const PetscInt ind = indperm ? indperm[preind] : preind; 7033 7034 if ((cind < cfdof) && (b == fcdofs[cind])) { 7035 indices[ind] = -(foff + b + 1); 7036 ++cind; 7037 } else { 7038 indices[ind] = foff + b - cind; 7039 } 7040 } 7041 } 7042 foffs[f] += fdof; 7043 } 7044 PetscFunctionReturn(0); 7045 } 7046 7047 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) 7048 { 7049 Mat cMat; 7050 PetscSection aSec, cSec; 7051 IS aIS; 7052 PetscInt aStart = -1, aEnd = -1; 7053 const PetscInt *anchors; 7054 PetscInt numFields, f, p, q, newP = 0; 7055 PetscInt newNumPoints = 0, newNumIndices = 0; 7056 PetscInt *newPoints, *indices, *newIndices; 7057 PetscInt maxAnchor, maxDof; 7058 PetscInt newOffsets[32]; 7059 PetscInt *pointMatOffsets[32]; 7060 PetscInt *newPointOffsets[32]; 7061 PetscScalar *pointMat[32]; 7062 PetscScalar *newValues = NULL, *tmpValues; 7063 PetscBool anyConstrained = PETSC_FALSE; 7064 7065 PetscFunctionBegin; 7066 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7067 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7068 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7069 7070 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7071 /* if there are point-to-point constraints */ 7072 if (aSec) { 7073 PetscCall(PetscArrayzero(newOffsets, 32)); 7074 PetscCall(ISGetIndices(aIS, &anchors)); 7075 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7076 /* figure out how many points are going to be in the new element matrix 7077 * (we allow double counting, because it's all just going to be summed 7078 * into the global matrix anyway) */ 7079 for (p = 0; p < 2 * numPoints; p += 2) { 7080 PetscInt b = points[p]; 7081 PetscInt bDof = 0, bSecDof; 7082 7083 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7084 if (!bSecDof) continue; 7085 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7086 if (bDof) { 7087 /* this point is constrained */ 7088 /* it is going to be replaced by its anchors */ 7089 PetscInt bOff, q; 7090 7091 anyConstrained = PETSC_TRUE; 7092 newNumPoints += bDof; 7093 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7094 for (q = 0; q < bDof; q++) { 7095 PetscInt a = anchors[bOff + q]; 7096 PetscInt aDof; 7097 7098 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7099 newNumIndices += aDof; 7100 for (f = 0; f < numFields; ++f) { 7101 PetscInt fDof; 7102 7103 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7104 newOffsets[f + 1] += fDof; 7105 } 7106 } 7107 } else { 7108 /* this point is not constrained */ 7109 newNumPoints++; 7110 newNumIndices += bSecDof; 7111 for (f = 0; f < numFields; ++f) { 7112 PetscInt fDof; 7113 7114 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7115 newOffsets[f + 1] += fDof; 7116 } 7117 } 7118 } 7119 } 7120 if (!anyConstrained) { 7121 if (outNumPoints) *outNumPoints = 0; 7122 if (outNumIndices) *outNumIndices = 0; 7123 if (outPoints) *outPoints = NULL; 7124 if (outValues) *outValues = NULL; 7125 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7126 PetscFunctionReturn(0); 7127 } 7128 7129 if (outNumPoints) *outNumPoints = newNumPoints; 7130 if (outNumIndices) *outNumIndices = newNumIndices; 7131 7132 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7133 7134 if (!outPoints && !outValues) { 7135 if (offsets) { 7136 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7137 } 7138 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7139 PetscFunctionReturn(0); 7140 } 7141 7142 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7143 7144 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7145 7146 /* workspaces */ 7147 if (numFields) { 7148 for (f = 0; f < numFields; f++) { 7149 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7150 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7151 } 7152 } else { 7153 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7154 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7155 } 7156 7157 /* get workspaces for the point-to-point matrices */ 7158 if (numFields) { 7159 PetscInt totalOffset, totalMatOffset; 7160 7161 for (p = 0; p < numPoints; p++) { 7162 PetscInt b = points[2 * p]; 7163 PetscInt bDof = 0, bSecDof; 7164 7165 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7166 if (!bSecDof) { 7167 for (f = 0; f < numFields; f++) { 7168 newPointOffsets[f][p + 1] = 0; 7169 pointMatOffsets[f][p + 1] = 0; 7170 } 7171 continue; 7172 } 7173 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7174 if (bDof) { 7175 for (f = 0; f < numFields; f++) { 7176 PetscInt fDof, q, bOff, allFDof = 0; 7177 7178 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7179 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7180 for (q = 0; q < bDof; q++) { 7181 PetscInt a = anchors[bOff + q]; 7182 PetscInt aFDof; 7183 7184 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7185 allFDof += aFDof; 7186 } 7187 newPointOffsets[f][p + 1] = allFDof; 7188 pointMatOffsets[f][p + 1] = fDof * allFDof; 7189 } 7190 } else { 7191 for (f = 0; f < numFields; f++) { 7192 PetscInt fDof; 7193 7194 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7195 newPointOffsets[f][p + 1] = fDof; 7196 pointMatOffsets[f][p + 1] = 0; 7197 } 7198 } 7199 } 7200 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7201 newPointOffsets[f][0] = totalOffset; 7202 pointMatOffsets[f][0] = totalMatOffset; 7203 for (p = 0; p < numPoints; p++) { 7204 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7205 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7206 } 7207 totalOffset = newPointOffsets[f][numPoints]; 7208 totalMatOffset = pointMatOffsets[f][numPoints]; 7209 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7210 } 7211 } else { 7212 for (p = 0; p < numPoints; p++) { 7213 PetscInt b = points[2 * p]; 7214 PetscInt bDof = 0, bSecDof; 7215 7216 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7217 if (!bSecDof) { 7218 newPointOffsets[0][p + 1] = 0; 7219 pointMatOffsets[0][p + 1] = 0; 7220 continue; 7221 } 7222 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7223 if (bDof) { 7224 PetscInt bOff, q, allDof = 0; 7225 7226 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7227 for (q = 0; q < bDof; q++) { 7228 PetscInt a = anchors[bOff + q], aDof; 7229 7230 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7231 allDof += aDof; 7232 } 7233 newPointOffsets[0][p + 1] = allDof; 7234 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7235 } else { 7236 newPointOffsets[0][p + 1] = bSecDof; 7237 pointMatOffsets[0][p + 1] = 0; 7238 } 7239 } 7240 newPointOffsets[0][0] = 0; 7241 pointMatOffsets[0][0] = 0; 7242 for (p = 0; p < numPoints; p++) { 7243 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7244 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7245 } 7246 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7247 } 7248 7249 /* output arrays */ 7250 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7251 7252 /* get the point-to-point matrices; construct newPoints */ 7253 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7254 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7255 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7256 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7257 if (numFields) { 7258 for (p = 0, newP = 0; p < numPoints; p++) { 7259 PetscInt b = points[2 * p]; 7260 PetscInt o = points[2 * p + 1]; 7261 PetscInt bDof = 0, bSecDof; 7262 7263 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7264 if (!bSecDof) continue; 7265 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7266 if (bDof) { 7267 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7268 7269 fStart[0] = 0; 7270 fEnd[0] = 0; 7271 for (f = 0; f < numFields; f++) { 7272 PetscInt fDof; 7273 7274 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7275 fStart[f + 1] = fStart[f] + fDof; 7276 fEnd[f + 1] = fStart[f + 1]; 7277 } 7278 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7279 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7280 7281 fAnchorStart[0] = 0; 7282 fAnchorEnd[0] = 0; 7283 for (f = 0; f < numFields; f++) { 7284 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7285 7286 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7287 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7288 } 7289 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7290 for (q = 0; q < bDof; q++) { 7291 PetscInt a = anchors[bOff + q], aOff; 7292 7293 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7294 newPoints[2 * (newP + q)] = a; 7295 newPoints[2 * (newP + q) + 1] = 0; 7296 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7297 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7298 } 7299 newP += bDof; 7300 7301 if (outValues) { 7302 /* get the point-to-point submatrix */ 7303 for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p])); 7304 } 7305 } else { 7306 newPoints[2 * newP] = b; 7307 newPoints[2 * newP + 1] = o; 7308 newP++; 7309 } 7310 } 7311 } else { 7312 for (p = 0; p < numPoints; p++) { 7313 PetscInt b = points[2 * p]; 7314 PetscInt o = points[2 * p + 1]; 7315 PetscInt bDof = 0, bSecDof; 7316 7317 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7318 if (!bSecDof) continue; 7319 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7320 if (bDof) { 7321 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7322 7323 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7324 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7325 7326 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7327 for (q = 0; q < bDof; q++) { 7328 PetscInt a = anchors[bOff + q], aOff; 7329 7330 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7331 7332 newPoints[2 * (newP + q)] = a; 7333 newPoints[2 * (newP + q) + 1] = 0; 7334 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7335 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7336 } 7337 newP += bDof; 7338 7339 /* get the point-to-point submatrix */ 7340 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7341 } else { 7342 newPoints[2 * newP] = b; 7343 newPoints[2 * newP + 1] = o; 7344 newP++; 7345 } 7346 } 7347 } 7348 7349 if (outValues) { 7350 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7351 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7352 /* multiply constraints on the right */ 7353 if (numFields) { 7354 for (f = 0; f < numFields; f++) { 7355 PetscInt oldOff = offsets[f]; 7356 7357 for (p = 0; p < numPoints; p++) { 7358 PetscInt cStart = newPointOffsets[f][p]; 7359 PetscInt b = points[2 * p]; 7360 PetscInt c, r, k; 7361 PetscInt dof; 7362 7363 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7364 if (!dof) continue; 7365 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7366 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7367 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7368 7369 for (r = 0; r < numIndices; r++) { 7370 for (c = 0; c < nCols; c++) { 7371 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7372 } 7373 } 7374 } else { 7375 /* copy this column as is */ 7376 for (r = 0; r < numIndices; r++) { 7377 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7378 } 7379 } 7380 oldOff += dof; 7381 } 7382 } 7383 } else { 7384 PetscInt oldOff = 0; 7385 for (p = 0; p < numPoints; p++) { 7386 PetscInt cStart = newPointOffsets[0][p]; 7387 PetscInt b = points[2 * p]; 7388 PetscInt c, r, k; 7389 PetscInt dof; 7390 7391 PetscCall(PetscSectionGetDof(section, b, &dof)); 7392 if (!dof) continue; 7393 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7394 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7395 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7396 7397 for (r = 0; r < numIndices; r++) { 7398 for (c = 0; c < nCols; c++) { 7399 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7400 } 7401 } 7402 } else { 7403 /* copy this column as is */ 7404 for (r = 0; r < numIndices; r++) { 7405 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7406 } 7407 } 7408 oldOff += dof; 7409 } 7410 } 7411 7412 if (multiplyLeft) { 7413 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7414 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7415 /* multiply constraints transpose on the left */ 7416 if (numFields) { 7417 for (f = 0; f < numFields; f++) { 7418 PetscInt oldOff = offsets[f]; 7419 7420 for (p = 0; p < numPoints; p++) { 7421 PetscInt rStart = newPointOffsets[f][p]; 7422 PetscInt b = points[2 * p]; 7423 PetscInt c, r, k; 7424 PetscInt dof; 7425 7426 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7427 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7428 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7429 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7430 7431 for (r = 0; r < nRows; r++) { 7432 for (c = 0; c < newNumIndices; c++) { 7433 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7434 } 7435 } 7436 } else { 7437 /* copy this row as is */ 7438 for (r = 0; r < dof; r++) { 7439 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7440 } 7441 } 7442 oldOff += dof; 7443 } 7444 } 7445 } else { 7446 PetscInt oldOff = 0; 7447 7448 for (p = 0; p < numPoints; p++) { 7449 PetscInt rStart = newPointOffsets[0][p]; 7450 PetscInt b = points[2 * p]; 7451 PetscInt c, r, k; 7452 PetscInt dof; 7453 7454 PetscCall(PetscSectionGetDof(section, b, &dof)); 7455 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7456 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7457 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7458 7459 for (r = 0; r < nRows; r++) { 7460 for (c = 0; c < newNumIndices; c++) { 7461 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7462 } 7463 } 7464 } else { 7465 /* copy this row as is */ 7466 for (r = 0; r < dof; r++) { 7467 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7468 } 7469 } 7470 oldOff += dof; 7471 } 7472 } 7473 7474 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7475 } else { 7476 newValues = tmpValues; 7477 } 7478 } 7479 7480 /* clean up */ 7481 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7482 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7483 7484 if (numFields) { 7485 for (f = 0; f < numFields; f++) { 7486 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7487 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7488 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7489 } 7490 } else { 7491 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7492 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7493 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7494 } 7495 PetscCall(ISRestoreIndices(aIS, &anchors)); 7496 7497 /* output */ 7498 if (outPoints) { 7499 *outPoints = newPoints; 7500 } else { 7501 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7502 } 7503 if (outValues) *outValues = newValues; 7504 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7505 PetscFunctionReturn(0); 7506 } 7507 7508 /*@C 7509 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7510 7511 Not collective 7512 7513 Input Parameters: 7514 + dm - The DM 7515 . section - The PetscSection describing the points (a local section) 7516 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7517 . point - The point defining the closure 7518 - useClPerm - Use the closure point permutation if available 7519 7520 Output Parameters: 7521 + numIndices - The number of dof indices in the closure of point with the input sections 7522 . indices - The dof indices 7523 . outOffsets - Array to write the field offsets into, or NULL 7524 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7525 7526 Notes: 7527 Must call DMPlexRestoreClosureIndices() to free allocated memory 7528 7529 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7530 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7531 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7532 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7533 indices (with the above semantics) are implied. 7534 7535 Level: advanced 7536 7537 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7538 @*/ 7539 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7540 { 7541 /* Closure ordering */ 7542 PetscSection clSection; 7543 IS clPoints; 7544 const PetscInt *clp; 7545 PetscInt *points; 7546 const PetscInt *clperm = NULL; 7547 /* Dof permutation and sign flips */ 7548 const PetscInt **perms[32] = {NULL}; 7549 const PetscScalar **flips[32] = {NULL}; 7550 PetscScalar *valCopy = NULL; 7551 /* Hanging node constraints */ 7552 PetscInt *pointsC = NULL; 7553 PetscScalar *valuesC = NULL; 7554 PetscInt NclC, NiC; 7555 7556 PetscInt *idx; 7557 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7558 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7559 7560 PetscFunctionBeginHot; 7561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7562 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7563 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7564 if (numIndices) PetscValidIntPointer(numIndices, 6); 7565 if (indices) PetscValidPointer(indices, 7); 7566 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7567 if (values) PetscValidPointer(values, 9); 7568 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7569 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7570 PetscCall(PetscArrayzero(offsets, 32)); 7571 /* 1) Get points in closure */ 7572 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7573 if (useClPerm) { 7574 PetscInt depth, clsize; 7575 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7576 for (clsize = 0, p = 0; p < Ncl; p++) { 7577 PetscInt dof; 7578 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7579 clsize += dof; 7580 } 7581 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7582 } 7583 /* 2) Get number of indices on these points and field offsets from section */ 7584 for (p = 0; p < Ncl * 2; p += 2) { 7585 PetscInt dof, fdof; 7586 7587 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7588 for (f = 0; f < Nf; ++f) { 7589 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7590 offsets[f + 1] += fdof; 7591 } 7592 Ni += dof; 7593 } 7594 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7595 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7596 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7597 for (f = 0; f < PetscMax(1, Nf); ++f) { 7598 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7599 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7600 /* may need to apply sign changes to the element matrix */ 7601 if (values && flips[f]) { 7602 PetscInt foffset = offsets[f]; 7603 7604 for (p = 0; p < Ncl; ++p) { 7605 PetscInt pnt = points[2 * p], fdof; 7606 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7607 7608 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7609 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7610 if (flip) { 7611 PetscInt i, j, k; 7612 7613 if (!valCopy) { 7614 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7615 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7616 *values = valCopy; 7617 } 7618 for (i = 0; i < fdof; ++i) { 7619 PetscScalar fval = flip[i]; 7620 7621 for (k = 0; k < Ni; ++k) { 7622 valCopy[Ni * (foffset + i) + k] *= fval; 7623 valCopy[Ni * k + (foffset + i)] *= fval; 7624 } 7625 } 7626 } 7627 foffset += fdof; 7628 } 7629 } 7630 } 7631 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7632 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7633 if (NclC) { 7634 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7635 for (f = 0; f < PetscMax(1, Nf); ++f) { 7636 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7637 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7638 } 7639 for (f = 0; f < PetscMax(1, Nf); ++f) { 7640 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7641 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7642 } 7643 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7644 Ncl = NclC; 7645 Ni = NiC; 7646 points = pointsC; 7647 if (values) *values = valuesC; 7648 } 7649 /* 5) Calculate indices */ 7650 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7651 if (Nf) { 7652 PetscInt idxOff; 7653 PetscBool useFieldOffsets; 7654 7655 if (outOffsets) { 7656 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7657 } 7658 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7659 if (useFieldOffsets) { 7660 for (p = 0; p < Ncl; ++p) { 7661 const PetscInt pnt = points[p * 2]; 7662 7663 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7664 } 7665 } else { 7666 for (p = 0; p < Ncl; ++p) { 7667 const PetscInt pnt = points[p * 2]; 7668 7669 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7670 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7671 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7672 * global section. */ 7673 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7674 } 7675 } 7676 } else { 7677 PetscInt off = 0, idxOff; 7678 7679 for (p = 0; p < Ncl; ++p) { 7680 const PetscInt pnt = points[p * 2]; 7681 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7682 7683 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7684 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7685 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7686 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7687 } 7688 } 7689 /* 6) Cleanup */ 7690 for (f = 0; f < PetscMax(1, Nf); ++f) { 7691 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7692 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7693 } 7694 if (NclC) { 7695 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7696 } else { 7697 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7698 } 7699 7700 if (numIndices) *numIndices = Ni; 7701 if (indices) *indices = idx; 7702 PetscFunctionReturn(0); 7703 } 7704 7705 /*@C 7706 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7707 7708 Not collective 7709 7710 Input Parameters: 7711 + dm - The DM 7712 . section - The PetscSection describing the points (a local section) 7713 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7714 . point - The point defining the closure 7715 - useClPerm - Use the closure point permutation if available 7716 7717 Output Parameters: 7718 + numIndices - The number of dof indices in the closure of point with the input sections 7719 . indices - The dof indices 7720 . outOffsets - Array to write the field offsets into, or NULL 7721 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7722 7723 Notes: 7724 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7725 7726 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7727 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7728 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7729 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7730 indices (with the above semantics) are implied. 7731 7732 Level: advanced 7733 7734 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7735 @*/ 7736 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7737 { 7738 PetscFunctionBegin; 7739 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7740 PetscValidPointer(indices, 7); 7741 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7742 PetscFunctionReturn(0); 7743 } 7744 7745 /*@C 7746 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7747 7748 Not collective 7749 7750 Input Parameters: 7751 + dm - The DM 7752 . section - The section describing the layout in v, or NULL to use the default section 7753 . globalSection - The section describing the layout in v, or NULL to use the default global section 7754 . A - The matrix 7755 . point - The point in the DM 7756 . values - The array of values 7757 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7758 7759 Fortran Notes: 7760 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7761 7762 Level: intermediate 7763 7764 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7765 @*/ 7766 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7767 { 7768 DM_Plex *mesh = (DM_Plex *)dm->data; 7769 PetscInt *indices; 7770 PetscInt numIndices; 7771 const PetscScalar *valuesOrig = values; 7772 PetscErrorCode ierr; 7773 7774 PetscFunctionBegin; 7775 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7776 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7777 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7778 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7779 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7780 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7781 7782 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7783 7784 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7785 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7786 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7787 if (ierr) { 7788 PetscMPIInt rank; 7789 7790 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7791 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7792 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7793 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7794 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7795 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7796 } 7797 if (mesh->printFEM > 1) { 7798 PetscInt i; 7799 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7800 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7801 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7802 } 7803 7804 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7805 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7806 PetscFunctionReturn(0); 7807 } 7808 7809 /*@C 7810 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7811 7812 Not collective 7813 7814 Input Parameters: 7815 + dmRow - The DM for the row fields 7816 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7817 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7818 . dmCol - The DM for the column fields 7819 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7820 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7821 . A - The matrix 7822 . point - The point in the DMs 7823 . values - The array of values 7824 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7825 7826 Level: intermediate 7827 7828 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7829 @*/ 7830 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7831 { 7832 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7833 PetscInt *indicesRow, *indicesCol; 7834 PetscInt numIndicesRow, numIndicesCol; 7835 const PetscScalar *valuesOrig = values; 7836 PetscErrorCode ierr; 7837 7838 PetscFunctionBegin; 7839 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7840 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7841 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7842 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7843 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7844 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7845 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7846 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7847 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7848 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7849 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7850 7851 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7852 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7853 7854 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7855 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7856 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7857 if (ierr) { 7858 PetscMPIInt rank; 7859 7860 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7861 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7862 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7863 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7864 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7865 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7866 } 7867 7868 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7869 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7870 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7871 PetscFunctionReturn(0); 7872 } 7873 7874 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7875 { 7876 DM_Plex *mesh = (DM_Plex *)dmf->data; 7877 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7878 PetscInt *cpoints = NULL; 7879 PetscInt *findices, *cindices; 7880 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7881 PetscInt foffsets[32], coffsets[32]; 7882 DMPolytopeType ct; 7883 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7884 PetscErrorCode ierr; 7885 7886 PetscFunctionBegin; 7887 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7888 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7889 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7890 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7891 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7892 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7893 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7894 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7895 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7896 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7897 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7898 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7899 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7900 PetscCall(PetscArrayzero(foffsets, 32)); 7901 PetscCall(PetscArrayzero(coffsets, 32)); 7902 /* Column indices */ 7903 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7904 maxFPoints = numCPoints; 7905 /* Compress out points not in the section */ 7906 /* TODO: Squeeze out points with 0 dof as well */ 7907 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7908 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7909 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7910 cpoints[q * 2] = cpoints[p]; 7911 cpoints[q * 2 + 1] = cpoints[p + 1]; 7912 ++q; 7913 } 7914 } 7915 numCPoints = q; 7916 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7917 PetscInt fdof; 7918 7919 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7920 if (!dof) continue; 7921 for (f = 0; f < numFields; ++f) { 7922 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7923 coffsets[f + 1] += fdof; 7924 } 7925 numCIndices += dof; 7926 } 7927 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7928 /* Row indices */ 7929 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7930 { 7931 DMPlexTransform tr; 7932 DMPolytopeType *rct; 7933 PetscInt *rsize, *rcone, *rornt, Nt; 7934 7935 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7936 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7937 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7938 numSubcells = rsize[Nt - 1]; 7939 PetscCall(DMPlexTransformDestroy(&tr)); 7940 } 7941 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7942 for (r = 0, q = 0; r < numSubcells; ++r) { 7943 /* TODO Map from coarse to fine cells */ 7944 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7945 /* Compress out points not in the section */ 7946 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7947 for (p = 0; p < numFPoints * 2; p += 2) { 7948 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7949 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7950 if (!dof) continue; 7951 for (s = 0; s < q; ++s) 7952 if (fpoints[p] == ftotpoints[s * 2]) break; 7953 if (s < q) continue; 7954 ftotpoints[q * 2] = fpoints[p]; 7955 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7956 ++q; 7957 } 7958 } 7959 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7960 } 7961 numFPoints = q; 7962 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7963 PetscInt fdof; 7964 7965 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7966 if (!dof) continue; 7967 for (f = 0; f < numFields; ++f) { 7968 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7969 foffsets[f + 1] += fdof; 7970 } 7971 numFIndices += dof; 7972 } 7973 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7974 7975 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7976 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7977 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7978 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7979 if (numFields) { 7980 const PetscInt **permsF[32] = {NULL}; 7981 const PetscInt **permsC[32] = {NULL}; 7982 7983 for (f = 0; f < numFields; f++) { 7984 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7985 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7986 } 7987 for (p = 0; p < numFPoints; p++) { 7988 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7989 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7990 } 7991 for (p = 0; p < numCPoints; p++) { 7992 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7993 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7994 } 7995 for (f = 0; f < numFields; f++) { 7996 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7997 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7998 } 7999 } else { 8000 const PetscInt **permsF = NULL; 8001 const PetscInt **permsC = NULL; 8002 8003 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8004 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8005 for (p = 0, off = 0; p < numFPoints; p++) { 8006 const PetscInt *perm = permsF ? permsF[p] : NULL; 8007 8008 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8009 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8010 } 8011 for (p = 0, off = 0; p < numCPoints; p++) { 8012 const PetscInt *perm = permsC ? permsC[p] : NULL; 8013 8014 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8015 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8016 } 8017 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8018 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8019 } 8020 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8021 /* TODO: flips */ 8022 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8023 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8024 if (ierr) { 8025 PetscMPIInt rank; 8026 8027 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8028 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8029 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8030 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8031 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8032 } 8033 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8034 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8035 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8036 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8037 PetscFunctionReturn(0); 8038 } 8039 8040 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8041 { 8042 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8043 PetscInt *cpoints = NULL; 8044 PetscInt foffsets[32], coffsets[32]; 8045 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8046 DMPolytopeType ct; 8047 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8048 8049 PetscFunctionBegin; 8050 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8051 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8052 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8053 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8054 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8055 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8056 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8057 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8058 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8059 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8060 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8061 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8062 PetscCall(PetscArrayzero(foffsets, 32)); 8063 PetscCall(PetscArrayzero(coffsets, 32)); 8064 /* Column indices */ 8065 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8066 maxFPoints = numCPoints; 8067 /* Compress out points not in the section */ 8068 /* TODO: Squeeze out points with 0 dof as well */ 8069 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8070 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8071 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8072 cpoints[q * 2] = cpoints[p]; 8073 cpoints[q * 2 + 1] = cpoints[p + 1]; 8074 ++q; 8075 } 8076 } 8077 numCPoints = q; 8078 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8079 PetscInt fdof; 8080 8081 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8082 if (!dof) continue; 8083 for (f = 0; f < numFields; ++f) { 8084 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8085 coffsets[f + 1] += fdof; 8086 } 8087 numCIndices += dof; 8088 } 8089 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8090 /* Row indices */ 8091 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8092 { 8093 DMPlexTransform tr; 8094 DMPolytopeType *rct; 8095 PetscInt *rsize, *rcone, *rornt, Nt; 8096 8097 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8098 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8099 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8100 numSubcells = rsize[Nt - 1]; 8101 PetscCall(DMPlexTransformDestroy(&tr)); 8102 } 8103 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8104 for (r = 0, q = 0; r < numSubcells; ++r) { 8105 /* TODO Map from coarse to fine cells */ 8106 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8107 /* Compress out points not in the section */ 8108 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8109 for (p = 0; p < numFPoints * 2; p += 2) { 8110 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8111 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8112 if (!dof) continue; 8113 for (s = 0; s < q; ++s) 8114 if (fpoints[p] == ftotpoints[s * 2]) break; 8115 if (s < q) continue; 8116 ftotpoints[q * 2] = fpoints[p]; 8117 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8118 ++q; 8119 } 8120 } 8121 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8122 } 8123 numFPoints = q; 8124 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8125 PetscInt fdof; 8126 8127 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8128 if (!dof) continue; 8129 for (f = 0; f < numFields; ++f) { 8130 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8131 foffsets[f + 1] += fdof; 8132 } 8133 numFIndices += dof; 8134 } 8135 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8136 8137 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8138 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8139 if (numFields) { 8140 const PetscInt **permsF[32] = {NULL}; 8141 const PetscInt **permsC[32] = {NULL}; 8142 8143 for (f = 0; f < numFields; f++) { 8144 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8145 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8146 } 8147 for (p = 0; p < numFPoints; p++) { 8148 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8149 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8150 } 8151 for (p = 0; p < numCPoints; p++) { 8152 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8153 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8154 } 8155 for (f = 0; f < numFields; f++) { 8156 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8157 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8158 } 8159 } else { 8160 const PetscInt **permsF = NULL; 8161 const PetscInt **permsC = NULL; 8162 8163 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8164 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8165 for (p = 0, off = 0; p < numFPoints; p++) { 8166 const PetscInt *perm = permsF ? permsF[p] : NULL; 8167 8168 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8169 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8170 } 8171 for (p = 0, off = 0; p < numCPoints; p++) { 8172 const PetscInt *perm = permsC ? permsC[p] : NULL; 8173 8174 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8175 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8176 } 8177 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8178 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8179 } 8180 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8181 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8182 PetscFunctionReturn(0); 8183 } 8184 8185 /*@C 8186 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8187 8188 Input Parameter: 8189 . dm - The DMPlex object 8190 8191 Output Parameter: 8192 . cellHeight - The height of a cell 8193 8194 Level: developer 8195 8196 .seealso `DMPlexSetVTKCellHeight()` 8197 @*/ 8198 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8199 { 8200 DM_Plex *mesh = (DM_Plex *)dm->data; 8201 8202 PetscFunctionBegin; 8203 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8204 PetscValidIntPointer(cellHeight, 2); 8205 *cellHeight = mesh->vtkCellHeight; 8206 PetscFunctionReturn(0); 8207 } 8208 8209 /*@C 8210 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8211 8212 Input Parameters: 8213 + dm - The DMPlex object 8214 - cellHeight - The height of a cell 8215 8216 Level: developer 8217 8218 .seealso `DMPlexGetVTKCellHeight()` 8219 @*/ 8220 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8221 { 8222 DM_Plex *mesh = (DM_Plex *)dm->data; 8223 8224 PetscFunctionBegin; 8225 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8226 mesh->vtkCellHeight = cellHeight; 8227 PetscFunctionReturn(0); 8228 } 8229 8230 /*@ 8231 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8232 8233 Input Parameter: 8234 . dm - The DMPlex object 8235 8236 Output Parameters: 8237 + gcStart - The first ghost cell, or NULL 8238 - gcEnd - The upper bound on ghost cells, or NULL 8239 8240 Level: advanced 8241 8242 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8243 @*/ 8244 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8245 { 8246 DMLabel ctLabel; 8247 8248 PetscFunctionBegin; 8249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8250 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8251 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8252 // Reset label for fast lookup 8253 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8254 PetscFunctionReturn(0); 8255 } 8256 8257 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8258 { 8259 PetscSection section, globalSection; 8260 PetscInt *numbers, p; 8261 8262 PetscFunctionBegin; 8263 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8264 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8265 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8266 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8267 PetscCall(PetscSectionSetUp(section)); 8268 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8269 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8270 for (p = pStart; p < pEnd; ++p) { 8271 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8272 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8273 else numbers[p - pStart] += shift; 8274 } 8275 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8276 if (globalSize) { 8277 PetscLayout layout; 8278 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8279 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8280 PetscCall(PetscLayoutDestroy(&layout)); 8281 } 8282 PetscCall(PetscSectionDestroy(§ion)); 8283 PetscCall(PetscSectionDestroy(&globalSection)); 8284 PetscFunctionReturn(0); 8285 } 8286 8287 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8288 { 8289 PetscInt cellHeight, cStart, cEnd; 8290 8291 PetscFunctionBegin; 8292 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8293 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8294 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8295 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8296 PetscFunctionReturn(0); 8297 } 8298 8299 /*@ 8300 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8301 8302 Input Parameter: 8303 . dm - The DMPlex object 8304 8305 Output Parameter: 8306 . globalCellNumbers - Global cell numbers for all cells on this process 8307 8308 Level: developer 8309 8310 .seealso `DMPlexGetVertexNumbering()` 8311 @*/ 8312 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8313 { 8314 DM_Plex *mesh = (DM_Plex *)dm->data; 8315 8316 PetscFunctionBegin; 8317 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8318 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8319 *globalCellNumbers = mesh->globalCellNumbers; 8320 PetscFunctionReturn(0); 8321 } 8322 8323 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8324 { 8325 PetscInt vStart, vEnd; 8326 8327 PetscFunctionBegin; 8328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8329 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8330 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8331 PetscFunctionReturn(0); 8332 } 8333 8334 /*@ 8335 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8336 8337 Input Parameter: 8338 . dm - The DMPlex object 8339 8340 Output Parameter: 8341 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8342 8343 Level: developer 8344 8345 .seealso `DMPlexGetCellNumbering()` 8346 @*/ 8347 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8348 { 8349 DM_Plex *mesh = (DM_Plex *)dm->data; 8350 8351 PetscFunctionBegin; 8352 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8353 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8354 *globalVertexNumbers = mesh->globalVertexNumbers; 8355 PetscFunctionReturn(0); 8356 } 8357 8358 /*@ 8359 DMPlexCreatePointNumbering - Create a global numbering for all points. 8360 8361 Collective on dm 8362 8363 Input Parameter: 8364 . dm - The DMPlex object 8365 8366 Output Parameter: 8367 . globalPointNumbers - Global numbers for all points on this process 8368 8369 Notes: 8370 8371 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8372 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8373 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8374 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8375 8376 The partitioned mesh is 8377 ``` 8378 (2)--0--(3)--1--(4) (1)--0--(2) 8379 ``` 8380 and its global numbering is 8381 ``` 8382 (3)--0--(4)--1--(5)--2--(6) 8383 ``` 8384 Then the global numbering is provided as 8385 ``` 8386 [0] Number of indices in set 5 8387 [0] 0 0 8388 [0] 1 1 8389 [0] 2 3 8390 [0] 3 4 8391 [0] 4 -6 8392 [1] Number of indices in set 3 8393 [1] 0 2 8394 [1] 1 5 8395 [1] 2 6 8396 ``` 8397 8398 Level: developer 8399 8400 .seealso `DMPlexGetCellNumbering()` 8401 @*/ 8402 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8403 { 8404 IS nums[4]; 8405 PetscInt depths[4], gdepths[4], starts[4]; 8406 PetscInt depth, d, shift = 0; 8407 PetscBool empty = PETSC_FALSE; 8408 8409 PetscFunctionBegin; 8410 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8411 PetscCall(DMPlexGetDepth(dm, &depth)); 8412 // For unstratified meshes use dim instead of depth 8413 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8414 // If any stratum is empty, we must mark all empty 8415 for (d = 0; d <= depth; ++d) { 8416 PetscInt end; 8417 8418 depths[d] = depth - d; 8419 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8420 if (!(starts[d] - end)) empty = PETSC_TRUE; 8421 } 8422 if (empty) 8423 for (d = 0; d <= depth; ++d) { 8424 depths[d] = -1; 8425 starts[d] = -1; 8426 } 8427 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8428 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8429 for (d = 0; d <= depth; ++d) PetscCheck(starts[d] < 0 || depths[d] == gdepths[d], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected depth %" PetscInt_FMT ", found %" PetscInt_FMT, depths[d], gdepths[d]); 8430 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8431 for (d = 0; d <= depth; ++d) { 8432 PetscInt pStart, pEnd, gsize; 8433 8434 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8435 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8436 shift += gsize; 8437 } 8438 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8439 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8440 PetscFunctionReturn(0); 8441 } 8442 8443 /*@ 8444 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8445 8446 Input Parameter: 8447 . dm - The DMPlex object 8448 8449 Output Parameter: 8450 . ranks - The rank field 8451 8452 Options Database Keys: 8453 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8454 8455 Level: intermediate 8456 8457 .seealso: `DMView()` 8458 @*/ 8459 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8460 { 8461 DM rdm; 8462 PetscFE fe; 8463 PetscScalar *r; 8464 PetscMPIInt rank; 8465 DMPolytopeType ct; 8466 PetscInt dim, cStart, cEnd, c; 8467 PetscBool simplex; 8468 8469 PetscFunctionBeginUser; 8470 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8471 PetscValidPointer(ranks, 2); 8472 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8473 PetscCall(DMClone(dm, &rdm)); 8474 PetscCall(DMGetDimension(rdm, &dim)); 8475 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8476 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8477 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8478 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8479 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8480 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8481 PetscCall(PetscFEDestroy(&fe)); 8482 PetscCall(DMCreateDS(rdm)); 8483 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8484 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8485 PetscCall(VecGetArray(*ranks, &r)); 8486 for (c = cStart; c < cEnd; ++c) { 8487 PetscScalar *lr; 8488 8489 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8490 if (lr) *lr = rank; 8491 } 8492 PetscCall(VecRestoreArray(*ranks, &r)); 8493 PetscCall(DMDestroy(&rdm)); 8494 PetscFunctionReturn(0); 8495 } 8496 8497 /*@ 8498 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8499 8500 Input Parameters: 8501 + dm - The DMPlex 8502 - label - The DMLabel 8503 8504 Output Parameter: 8505 . val - The label value field 8506 8507 Options Database Keys: 8508 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8509 8510 Level: intermediate 8511 8512 .seealso: `DMView()` 8513 @*/ 8514 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8515 { 8516 DM rdm; 8517 PetscFE fe; 8518 PetscScalar *v; 8519 PetscInt dim, cStart, cEnd, c; 8520 8521 PetscFunctionBeginUser; 8522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8523 PetscValidPointer(label, 2); 8524 PetscValidPointer(val, 3); 8525 PetscCall(DMClone(dm, &rdm)); 8526 PetscCall(DMGetDimension(rdm, &dim)); 8527 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8528 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8529 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8530 PetscCall(PetscFEDestroy(&fe)); 8531 PetscCall(DMCreateDS(rdm)); 8532 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8533 PetscCall(DMCreateGlobalVector(rdm, val)); 8534 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8535 PetscCall(VecGetArray(*val, &v)); 8536 for (c = cStart; c < cEnd; ++c) { 8537 PetscScalar *lv; 8538 PetscInt cval; 8539 8540 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8541 PetscCall(DMLabelGetValue(label, c, &cval)); 8542 *lv = cval; 8543 } 8544 PetscCall(VecRestoreArray(*val, &v)); 8545 PetscCall(DMDestroy(&rdm)); 8546 PetscFunctionReturn(0); 8547 } 8548 8549 /*@ 8550 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8551 8552 Input Parameter: 8553 . dm - The DMPlex object 8554 8555 Notes: 8556 This is a useful diagnostic when creating meshes programmatically. 8557 8558 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8559 8560 Level: developer 8561 8562 .seealso: `DMCreate()`, `DMSetFromOptions()` 8563 @*/ 8564 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8565 { 8566 PetscSection coneSection, supportSection; 8567 const PetscInt *cone, *support; 8568 PetscInt coneSize, c, supportSize, s; 8569 PetscInt pStart, pEnd, p, pp, csize, ssize; 8570 PetscBool storagecheck = PETSC_TRUE; 8571 8572 PetscFunctionBegin; 8573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8574 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8575 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8576 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8577 /* Check that point p is found in the support of its cone points, and vice versa */ 8578 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8579 for (p = pStart; p < pEnd; ++p) { 8580 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8581 PetscCall(DMPlexGetCone(dm, p, &cone)); 8582 for (c = 0; c < coneSize; ++c) { 8583 PetscBool dup = PETSC_FALSE; 8584 PetscInt d; 8585 for (d = c - 1; d >= 0; --d) { 8586 if (cone[c] == cone[d]) { 8587 dup = PETSC_TRUE; 8588 break; 8589 } 8590 } 8591 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8592 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8593 for (s = 0; s < supportSize; ++s) { 8594 if (support[s] == p) break; 8595 } 8596 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8597 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8598 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8599 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8600 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8601 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8602 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8603 PetscCheck(!dup, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not repeatedly found in support of repeated cone point %" PetscInt_FMT, p, cone[c]); 8604 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8605 } 8606 } 8607 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8608 if (p != pp) { 8609 storagecheck = PETSC_FALSE; 8610 continue; 8611 } 8612 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8613 PetscCall(DMPlexGetSupport(dm, p, &support)); 8614 for (s = 0; s < supportSize; ++s) { 8615 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8616 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8617 for (c = 0; c < coneSize; ++c) { 8618 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8619 if (cone[c] != pp) { 8620 c = 0; 8621 break; 8622 } 8623 if (cone[c] == p) break; 8624 } 8625 if (c >= coneSize) { 8626 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8627 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8628 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8629 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8630 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8631 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8632 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8633 } 8634 } 8635 } 8636 if (storagecheck) { 8637 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8638 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8639 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8640 } 8641 PetscFunctionReturn(0); 8642 } 8643 8644 /* 8645 For submeshes with cohesive cells (see DMPlexConstructCohesiveCells()), we allow a special case where some of the boundary of a face (edges and vertices) are not duplicated. We call these special boundary points "unsplit", since the same edge or vertex appears in both copies of the face. These unsplit points throw off our counting, so we have to explicitly account for them here. 8646 */ 8647 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8648 { 8649 DMPolytopeType cct; 8650 PetscInt ptpoints[4]; 8651 const PetscInt *cone, *ccone, *ptcone; 8652 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8653 8654 PetscFunctionBegin; 8655 *unsplit = 0; 8656 switch (ct) { 8657 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8658 ptpoints[npt++] = c; 8659 break; 8660 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8661 PetscCall(DMPlexGetCone(dm, c, &cone)); 8662 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8663 for (cp = 0; cp < coneSize; ++cp) { 8664 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8665 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8666 } 8667 break; 8668 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8669 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8670 PetscCall(DMPlexGetCone(dm, c, &cone)); 8671 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8672 for (cp = 0; cp < coneSize; ++cp) { 8673 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8674 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8675 for (ccp = 0; ccp < cconeSize; ++ccp) { 8676 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8677 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8678 PetscInt p; 8679 for (p = 0; p < npt; ++p) 8680 if (ptpoints[p] == ccone[ccp]) break; 8681 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8682 } 8683 } 8684 } 8685 break; 8686 default: 8687 break; 8688 } 8689 for (pt = 0; pt < npt; ++pt) { 8690 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8691 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8692 } 8693 PetscFunctionReturn(0); 8694 } 8695 8696 /*@ 8697 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8698 8699 Input Parameters: 8700 + dm - The DMPlex object 8701 - cellHeight - Normally 0 8702 8703 Notes: 8704 This is a useful diagnostic when creating meshes programmatically. 8705 Currently applicable only to homogeneous simplex or tensor meshes. 8706 8707 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8708 8709 Level: developer 8710 8711 .seealso: `DMCreate()`, `DMSetFromOptions()` 8712 @*/ 8713 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8714 { 8715 DMPlexInterpolatedFlag interp; 8716 DMPolytopeType ct; 8717 PetscInt vStart, vEnd, cStart, cEnd, c; 8718 8719 PetscFunctionBegin; 8720 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8721 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8722 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8723 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8724 for (c = cStart; c < cEnd; ++c) { 8725 PetscInt *closure = NULL; 8726 PetscInt coneSize, closureSize, cl, Nv = 0; 8727 8728 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8729 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8730 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8731 if (interp == DMPLEX_INTERPOLATED_FULL) { 8732 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8733 PetscCheck(coneSize == DMPolytopeTypeGetConeSize(ct), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has cone size %" PetscInt_FMT " != %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, DMPolytopeTypeGetConeSize(ct)); 8734 } 8735 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8736 for (cl = 0; cl < closureSize * 2; cl += 2) { 8737 const PetscInt p = closure[cl]; 8738 if ((p >= vStart) && (p < vEnd)) ++Nv; 8739 } 8740 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8741 /* Special Case: Tensor faces with identified vertices */ 8742 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8743 PetscInt unsplit; 8744 8745 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8746 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8747 } 8748 PetscCheck(Nv == DMPolytopeTypeGetNumVertices(ct), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices != %" PetscInt_FMT, c, DMPolytopeTypes[ct], Nv, DMPolytopeTypeGetNumVertices(ct)); 8749 } 8750 PetscFunctionReturn(0); 8751 } 8752 8753 /*@ 8754 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8755 8756 Collective 8757 8758 Input Parameters: 8759 + dm - The DMPlex object 8760 - cellHeight - Normally 0 8761 8762 Notes: 8763 This is a useful diagnostic when creating meshes programmatically. 8764 This routine is only relevant for meshes that are fully interpolated across all ranks. 8765 It will error out if a partially interpolated mesh is given on some rank. 8766 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8767 8768 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8769 8770 Level: developer 8771 8772 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8773 @*/ 8774 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8775 { 8776 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8777 DMPlexInterpolatedFlag interpEnum; 8778 8779 PetscFunctionBegin; 8780 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8781 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8782 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8783 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8784 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8785 PetscFunctionReturn(0); 8786 } 8787 8788 PetscCall(DMGetDimension(dm, &dim)); 8789 PetscCall(DMPlexGetDepth(dm, &depth)); 8790 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8791 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8792 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8793 for (c = cStart; c < cEnd; ++c) { 8794 const PetscInt *cone, *ornt, *faceSizes, *faces; 8795 const DMPolytopeType *faceTypes; 8796 DMPolytopeType ct; 8797 PetscInt numFaces, coneSize, f; 8798 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8799 8800 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8801 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8802 if (unsplit) continue; 8803 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8804 PetscCall(DMPlexGetCone(dm, c, &cone)); 8805 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8806 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8807 for (cl = 0; cl < closureSize * 2; cl += 2) { 8808 const PetscInt p = closure[cl]; 8809 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8810 } 8811 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8812 PetscCheck(coneSize == numFaces, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " faces but should have %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, numFaces); 8813 for (f = 0; f < numFaces; ++f) { 8814 DMPolytopeType fct; 8815 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8816 8817 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8818 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8819 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8820 const PetscInt p = fclosure[cl]; 8821 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8822 } 8823 PetscCheck(fnumCorners == faceSizes[f], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices but should have %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, c, DMPolytopeTypes[ct], fnumCorners, faceSizes[f]); 8824 for (v = 0; v < fnumCorners; ++v) { 8825 if (fclosure[v] != faces[fOff + v]) { 8826 PetscInt v1; 8827 8828 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8829 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8830 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8831 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8832 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8833 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ", ornt %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s vertex %" PetscInt_FMT ", %" PetscInt_FMT " != %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, ornt[f], c, DMPolytopeTypes[ct], v, fclosure[v], faces[fOff + v]); 8834 } 8835 } 8836 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8837 fOff += faceSizes[f]; 8838 } 8839 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8840 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8841 } 8842 } 8843 PetscFunctionReturn(0); 8844 } 8845 8846 /*@ 8847 DMPlexCheckGeometry - Check the geometry of mesh cells 8848 8849 Input Parameter: 8850 . dm - The DMPlex object 8851 8852 Notes: 8853 This is a useful diagnostic when creating meshes programmatically. 8854 8855 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8856 8857 Level: developer 8858 8859 .seealso: `DMCreate()`, `DMSetFromOptions()` 8860 @*/ 8861 PetscErrorCode DMPlexCheckGeometry(DM dm) 8862 { 8863 Vec coordinates; 8864 PetscReal detJ, J[9], refVol = 1.0; 8865 PetscReal vol; 8866 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8867 8868 PetscFunctionBegin; 8869 PetscCall(DMGetDimension(dm, &dim)); 8870 PetscCall(DMGetCoordinateDim(dm, &dE)); 8871 if (dim != dE) PetscFunctionReturn(0); 8872 PetscCall(DMPlexGetDepth(dm, &depth)); 8873 for (d = 0; d < dim; ++d) refVol *= 2.0; 8874 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8875 /* Make sure local coordinates are created, because that step is collective */ 8876 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8877 for (c = cStart; c < cEnd; ++c) { 8878 DMPolytopeType ct; 8879 PetscInt unsplit; 8880 PetscBool ignoreZeroVol = PETSC_FALSE; 8881 8882 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8883 switch (ct) { 8884 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8885 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8886 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8887 ignoreZeroVol = PETSC_TRUE; 8888 break; 8889 default: 8890 break; 8891 } 8892 switch (ct) { 8893 case DM_POLYTOPE_TRI_PRISM: 8894 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8895 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8896 case DM_POLYTOPE_PYRAMID: 8897 continue; 8898 default: 8899 break; 8900 } 8901 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8902 if (unsplit) continue; 8903 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8904 PetscCheck(detJ >= -PETSC_SMALL && (detJ > 0.0 || ignoreZeroVol), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, |J| = %g", c, DMPolytopeTypes[ct], (double)detJ); 8905 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8906 /* This should work with periodicity since DG coordinates should be used */ 8907 if (depth > 1) { 8908 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8909 PetscCheck(vol >= -PETSC_SMALL && (vol > 0.0 || ignoreZeroVol), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, vol = %g", c, DMPolytopeTypes[ct], (double)vol); 8910 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8911 } 8912 } 8913 PetscFunctionReturn(0); 8914 } 8915 8916 /*@ 8917 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8918 8919 Collective 8920 8921 Input Parameters: 8922 + dm - The DMPlex object 8923 . pointSF - The Point SF, or NULL for Point SF attached to DM 8924 - allowExtraRoots - Flag to allow extra points not present in the DM 8925 8926 Notes: 8927 This is mainly intended for debugging/testing purposes. 8928 8929 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8930 8931 Extra roots can come from priodic cuts, where additional points appear on the boundary 8932 8933 Level: developer 8934 8935 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8936 @*/ 8937 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 8938 { 8939 PetscInt l, nleaves, nroots, overlap; 8940 const PetscInt *locals; 8941 const PetscSFNode *remotes; 8942 PetscBool distributed; 8943 MPI_Comm comm; 8944 PetscMPIInt rank; 8945 8946 PetscFunctionBegin; 8947 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8948 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8949 else pointSF = dm->sf; 8950 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8951 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8952 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8953 { 8954 PetscMPIInt mpiFlag; 8955 8956 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8957 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8958 } 8959 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8960 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8961 if (!distributed) { 8962 PetscCheck(nroots < 0 || nleaves == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Undistributed DMPlex cannot have non-empty PointSF (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8963 PetscFunctionReturn(0); 8964 } 8965 PetscCheck(nroots >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8966 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8967 8968 /* Check SF graph is compatible with DMPlex chart */ 8969 { 8970 PetscInt pStart, pEnd, maxLeaf; 8971 8972 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8973 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8974 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8975 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8976 } 8977 8978 /* Check Point SF has no local points referenced */ 8979 for (l = 0; l < nleaves; l++) { 8980 PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index); 8981 } 8982 8983 /* Check there are no cells in interface */ 8984 if (!overlap) { 8985 PetscInt cellHeight, cStart, cEnd; 8986 8987 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8988 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8989 for (l = 0; l < nleaves; ++l) { 8990 const PetscInt point = locals ? locals[l] : l; 8991 8992 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8993 } 8994 } 8995 8996 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8997 { 8998 const PetscInt *rootdegree; 8999 9000 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9001 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9002 for (l = 0; l < nleaves; ++l) { 9003 const PetscInt point = locals ? locals[l] : l; 9004 const PetscInt *cone; 9005 PetscInt coneSize, c, idx; 9006 9007 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9008 PetscCall(DMPlexGetCone(dm, point, &cone)); 9009 for (c = 0; c < coneSize; ++c) { 9010 if (!rootdegree[cone[c]]) { 9011 if (locals) { 9012 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9013 } else { 9014 idx = (cone[c] < nleaves) ? cone[c] : -1; 9015 } 9016 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9017 } 9018 } 9019 } 9020 } 9021 PetscFunctionReturn(0); 9022 } 9023 9024 /*@ 9025 DMPlexCheck - Perform various checks of Plex sanity 9026 9027 Input Parameter: 9028 . dm - The DMPlex object 9029 9030 Notes: 9031 This is a useful diagnostic when creating meshes programmatically. 9032 9033 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 9034 9035 Currently does not include DMPlexCheckCellShape(). 9036 9037 Level: developer 9038 9039 .seealso: DMCreate(), DMSetFromOptions() 9040 @*/ 9041 PetscErrorCode DMPlexCheck(DM dm) 9042 { 9043 PetscInt cellHeight; 9044 9045 PetscFunctionBegin; 9046 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9047 PetscCall(DMPlexCheckSymmetry(dm)); 9048 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9049 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9050 PetscCall(DMPlexCheckGeometry(dm)); 9051 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9052 PetscCall(DMPlexCheckInterfaceCones(dm)); 9053 PetscFunctionReturn(0); 9054 } 9055 9056 typedef struct cell_stats { 9057 PetscReal min, max, sum, squaresum; 9058 PetscInt count; 9059 } cell_stats_t; 9060 9061 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9062 { 9063 PetscInt i, N = *len; 9064 9065 for (i = 0; i < N; i++) { 9066 cell_stats_t *A = (cell_stats_t *)a; 9067 cell_stats_t *B = (cell_stats_t *)b; 9068 9069 B->min = PetscMin(A->min, B->min); 9070 B->max = PetscMax(A->max, B->max); 9071 B->sum += A->sum; 9072 B->squaresum += A->squaresum; 9073 B->count += A->count; 9074 } 9075 } 9076 9077 /*@ 9078 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9079 9080 Collective on dm 9081 9082 Input Parameters: 9083 + dm - The DMPlex object 9084 . output - If true, statistics will be displayed on stdout 9085 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 9086 9087 Notes: 9088 This is mainly intended for debugging/testing purposes. 9089 9090 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 9091 9092 Level: developer 9093 9094 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9095 @*/ 9096 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9097 { 9098 DM dmCoarse; 9099 cell_stats_t stats, globalStats; 9100 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9101 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9102 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9103 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9104 PetscMPIInt rank, size; 9105 9106 PetscFunctionBegin; 9107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9108 stats.min = PETSC_MAX_REAL; 9109 stats.max = PETSC_MIN_REAL; 9110 stats.sum = stats.squaresum = 0.; 9111 stats.count = 0; 9112 9113 PetscCallMPI(MPI_Comm_size(comm, &size)); 9114 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9115 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9116 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9117 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9118 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9119 for (c = cStart; c < cEnd; c++) { 9120 PetscInt i; 9121 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9122 9123 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9124 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9125 for (i = 0; i < PetscSqr(cdim); ++i) { 9126 frobJ += J[i] * J[i]; 9127 frobInvJ += invJ[i] * invJ[i]; 9128 } 9129 cond2 = frobJ * frobInvJ; 9130 cond = PetscSqrtReal(cond2); 9131 9132 stats.min = PetscMin(stats.min, cond); 9133 stats.max = PetscMax(stats.max, cond); 9134 stats.sum += cond; 9135 stats.squaresum += cond2; 9136 stats.count++; 9137 if (output && cond > limit) { 9138 PetscSection coordSection; 9139 Vec coordsLocal; 9140 PetscScalar *coords = NULL; 9141 PetscInt Nv, d, clSize, cl, *closure = NULL; 9142 9143 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9144 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9145 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9146 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9147 for (i = 0; i < Nv / cdim; ++i) { 9148 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9149 for (d = 0; d < cdim; ++d) { 9150 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9151 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9152 } 9153 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9154 } 9155 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9156 for (cl = 0; cl < clSize * 2; cl += 2) { 9157 const PetscInt edge = closure[cl]; 9158 9159 if ((edge >= eStart) && (edge < eEnd)) { 9160 PetscReal len; 9161 9162 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9163 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9164 } 9165 } 9166 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9167 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9168 } 9169 } 9170 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9171 9172 if (size > 1) { 9173 PetscMPIInt blockLengths[2] = {4, 1}; 9174 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9175 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9176 MPI_Op statReduce; 9177 9178 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9179 PetscCallMPI(MPI_Type_commit(&statType)); 9180 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9181 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9182 PetscCallMPI(MPI_Op_free(&statReduce)); 9183 PetscCallMPI(MPI_Type_free(&statType)); 9184 } else { 9185 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9186 } 9187 if (rank == 0) { 9188 count = globalStats.count; 9189 min = globalStats.min; 9190 max = globalStats.max; 9191 mean = globalStats.sum / globalStats.count; 9192 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9193 } 9194 9195 if (output) PetscCall(PetscPrintf(comm, "Mesh with %" PetscInt_FMT " cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double)min, (double)max, (double)mean, (double)stdev)); 9196 PetscCall(PetscFree2(J, invJ)); 9197 9198 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9199 if (dmCoarse) { 9200 PetscBool isplex; 9201 9202 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9203 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9204 } 9205 PetscFunctionReturn(0); 9206 } 9207 9208 /*@ 9209 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9210 orthogonal quality below given tolerance. 9211 9212 Collective on dm 9213 9214 Input Parameters: 9215 + dm - The DMPlex object 9216 . fv - Optional PetscFV object for pre-computed cell/face centroid information 9217 - atol - [0, 1] Absolute tolerance for tagging cells. 9218 9219 Output Parameters: 9220 + OrthQual - Vec containing orthogonal quality per cell 9221 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 9222 9223 Options Database Keys: 9224 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 9225 supported. 9226 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9227 9228 Notes: 9229 Orthogonal quality is given by the following formula: 9230 9231 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 9232 9233 Where A_i is the i'th face-normal vector, f_i is the vector from the cell centroid to the i'th face centroid, and c_i 9234 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9235 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9236 calculating the cosine of the angle between these vectors. 9237 9238 Orthogonal quality ranges from 1 (best) to 0 (worst). 9239 9240 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 9241 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9242 9243 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9244 9245 Level: intermediate 9246 9247 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 9248 @*/ 9249 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9250 { 9251 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9252 PetscInt *idx; 9253 PetscScalar *oqVals; 9254 const PetscScalar *cellGeomArr, *faceGeomArr; 9255 PetscReal *ci, *fi, *Ai; 9256 MPI_Comm comm; 9257 Vec cellgeom, facegeom; 9258 DM dmFace, dmCell; 9259 IS glob; 9260 ISLocalToGlobalMapping ltog; 9261 PetscViewer vwr; 9262 9263 PetscFunctionBegin; 9264 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9265 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9266 PetscValidPointer(OrthQual, 4); 9267 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9268 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9269 PetscCall(DMGetDimension(dm, &nc)); 9270 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9271 { 9272 DMPlexInterpolatedFlag interpFlag; 9273 9274 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9275 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9276 PetscMPIInt rank; 9277 9278 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9279 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9280 } 9281 } 9282 if (OrthQualLabel) { 9283 PetscValidPointer(OrthQualLabel, 5); 9284 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9285 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9286 } else { 9287 *OrthQualLabel = NULL; 9288 } 9289 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9290 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9291 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9292 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9293 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9294 PetscCall(VecCreate(comm, OrthQual)); 9295 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9296 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9297 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9298 PetscCall(VecSetUp(*OrthQual)); 9299 PetscCall(ISDestroy(&glob)); 9300 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9301 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9302 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9303 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9304 PetscCall(VecGetDM(cellgeom, &dmCell)); 9305 PetscCall(VecGetDM(facegeom, &dmFace)); 9306 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9307 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9308 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9309 PetscInt cellarr[2], *adj = NULL; 9310 PetscScalar *cArr, *fArr; 9311 PetscReal minvalc = 1.0, minvalf = 1.0; 9312 PetscFVCellGeom *cg; 9313 9314 idx[cellIter] = cell - cStart; 9315 cellarr[0] = cell; 9316 /* Make indexing into cellGeom easier */ 9317 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9318 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9319 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9320 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9321 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9322 PetscInt i; 9323 const PetscInt neigh = adj[cellneigh]; 9324 PetscReal normci = 0, normfi = 0, normai = 0; 9325 PetscFVCellGeom *cgneigh; 9326 PetscFVFaceGeom *fg; 9327 9328 /* Don't count ourselves in the neighbor list */ 9329 if (neigh == cell) continue; 9330 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9331 cellarr[1] = neigh; 9332 { 9333 PetscInt numcovpts; 9334 const PetscInt *covpts; 9335 9336 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9337 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9338 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9339 } 9340 9341 /* Compute c_i, f_i and their norms */ 9342 for (i = 0; i < nc; i++) { 9343 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9344 fi[i] = fg->centroid[i] - cg->centroid[i]; 9345 Ai[i] = fg->normal[i]; 9346 normci += PetscPowReal(ci[i], 2); 9347 normfi += PetscPowReal(fi[i], 2); 9348 normai += PetscPowReal(Ai[i], 2); 9349 } 9350 normci = PetscSqrtReal(normci); 9351 normfi = PetscSqrtReal(normfi); 9352 normai = PetscSqrtReal(normai); 9353 9354 /* Normalize and compute for each face-cell-normal pair */ 9355 for (i = 0; i < nc; i++) { 9356 ci[i] = ci[i] / normci; 9357 fi[i] = fi[i] / normfi; 9358 Ai[i] = Ai[i] / normai; 9359 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9360 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9361 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9362 } 9363 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9364 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9365 } 9366 PetscCall(PetscFree(adj)); 9367 PetscCall(PetscFree2(cArr, fArr)); 9368 /* Defer to cell if they're equal */ 9369 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9370 if (OrthQualLabel) { 9371 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9372 } 9373 } 9374 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9375 PetscCall(VecAssemblyBegin(*OrthQual)); 9376 PetscCall(VecAssemblyEnd(*OrthQual)); 9377 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9378 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9379 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9380 if (OrthQualLabel) { 9381 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9382 } 9383 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9384 PetscCall(PetscViewerDestroy(&vwr)); 9385 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9386 PetscFunctionReturn(0); 9387 } 9388 9389 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9390 * interpolator construction */ 9391 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9392 { 9393 PetscSection section, newSection, gsection; 9394 PetscSF sf; 9395 PetscBool hasConstraints, ghasConstraints; 9396 9397 PetscFunctionBegin; 9398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9399 PetscValidPointer(odm, 2); 9400 PetscCall(DMGetLocalSection(dm, §ion)); 9401 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9402 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9403 if (!ghasConstraints) { 9404 PetscCall(PetscObjectReference((PetscObject)dm)); 9405 *odm = dm; 9406 PetscFunctionReturn(0); 9407 } 9408 PetscCall(DMClone(dm, odm)); 9409 PetscCall(DMCopyFields(dm, *odm)); 9410 PetscCall(DMGetLocalSection(*odm, &newSection)); 9411 PetscCall(DMGetPointSF(*odm, &sf)); 9412 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9413 PetscCall(DMSetGlobalSection(*odm, gsection)); 9414 PetscCall(PetscSectionDestroy(&gsection)); 9415 PetscFunctionReturn(0); 9416 } 9417 9418 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9419 { 9420 DM dmco, dmfo; 9421 Mat interpo; 9422 Vec rscale; 9423 Vec cglobalo, clocal; 9424 Vec fglobal, fglobalo, flocal; 9425 PetscBool regular; 9426 9427 PetscFunctionBegin; 9428 PetscCall(DMGetFullDM(dmc, &dmco)); 9429 PetscCall(DMGetFullDM(dmf, &dmfo)); 9430 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9431 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9432 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9433 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9434 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9435 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9436 PetscCall(VecSet(cglobalo, 0.)); 9437 PetscCall(VecSet(clocal, 0.)); 9438 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9439 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9440 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9441 PetscCall(VecSet(fglobal, 0.)); 9442 PetscCall(VecSet(fglobalo, 0.)); 9443 PetscCall(VecSet(flocal, 0.)); 9444 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9445 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9446 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9447 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9448 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9449 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9450 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9451 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9452 *shift = fglobal; 9453 PetscCall(VecDestroy(&flocal)); 9454 PetscCall(VecDestroy(&fglobalo)); 9455 PetscCall(VecDestroy(&clocal)); 9456 PetscCall(VecDestroy(&cglobalo)); 9457 PetscCall(VecDestroy(&rscale)); 9458 PetscCall(MatDestroy(&interpo)); 9459 PetscCall(DMDestroy(&dmfo)); 9460 PetscCall(DMDestroy(&dmco)); 9461 PetscFunctionReturn(0); 9462 } 9463 9464 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9465 { 9466 PetscObject shifto; 9467 Vec shift; 9468 9469 PetscFunctionBegin; 9470 if (!interp) { 9471 Vec rscale; 9472 9473 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9474 PetscCall(VecDestroy(&rscale)); 9475 } else { 9476 PetscCall(PetscObjectReference((PetscObject)interp)); 9477 } 9478 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9479 if (!shifto) { 9480 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9481 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9482 shifto = (PetscObject)shift; 9483 PetscCall(VecDestroy(&shift)); 9484 } 9485 shift = (Vec)shifto; 9486 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9487 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9488 PetscCall(MatDestroy(&interp)); 9489 PetscFunctionReturn(0); 9490 } 9491 9492 /* Pointwise interpolation 9493 Just code FEM for now 9494 u^f = I u^c 9495 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9496 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9497 I_{ij} = psi^f_i phi^c_j 9498 */ 9499 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9500 { 9501 PetscSection gsc, gsf; 9502 PetscInt m, n; 9503 void *ctx; 9504 DM cdm; 9505 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9506 9507 PetscFunctionBegin; 9508 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9509 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9510 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9511 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9512 9513 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9514 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9515 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9516 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9517 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9518 9519 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9520 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9521 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9522 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9523 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9524 if (scaling) { 9525 /* Use naive scaling */ 9526 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9527 } 9528 PetscFunctionReturn(0); 9529 } 9530 9531 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9532 { 9533 VecScatter ctx; 9534 9535 PetscFunctionBegin; 9536 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9537 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9538 PetscCall(VecScatterDestroy(&ctx)); 9539 PetscFunctionReturn(0); 9540 } 9541 9542 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9543 { 9544 const PetscInt Nc = uOff[1] - uOff[0]; 9545 PetscInt c; 9546 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9547 } 9548 9549 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9550 { 9551 DM dmc; 9552 PetscDS ds; 9553 Vec ones, locmass; 9554 IS cellIS; 9555 PetscFormKey key; 9556 PetscInt depth; 9557 9558 PetscFunctionBegin; 9559 PetscCall(DMClone(dm, &dmc)); 9560 PetscCall(DMCopyDisc(dm, dmc)); 9561 PetscCall(DMGetDS(dmc, &ds)); 9562 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9563 PetscCall(DMCreateGlobalVector(dmc, mass)); 9564 PetscCall(DMGetLocalVector(dmc, &ones)); 9565 PetscCall(DMGetLocalVector(dmc, &locmass)); 9566 PetscCall(DMPlexGetDepth(dmc, &depth)); 9567 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9568 PetscCall(VecSet(locmass, 0.0)); 9569 PetscCall(VecSet(ones, 1.0)); 9570 key.label = NULL; 9571 key.value = 0; 9572 key.field = 0; 9573 key.part = 0; 9574 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9575 PetscCall(ISDestroy(&cellIS)); 9576 PetscCall(VecSet(*mass, 0.0)); 9577 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9578 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9579 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9580 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9581 PetscCall(DMDestroy(&dmc)); 9582 PetscFunctionReturn(0); 9583 } 9584 9585 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9586 { 9587 PetscSection gsc, gsf; 9588 PetscInt m, n; 9589 void *ctx; 9590 DM cdm; 9591 PetscBool regular; 9592 9593 PetscFunctionBegin; 9594 if (dmFine == dmCoarse) { 9595 DM dmc; 9596 PetscDS ds; 9597 PetscWeakForm wf; 9598 Vec u; 9599 IS cellIS; 9600 PetscFormKey key; 9601 PetscInt depth; 9602 9603 PetscCall(DMClone(dmFine, &dmc)); 9604 PetscCall(DMCopyDisc(dmFine, dmc)); 9605 PetscCall(DMGetDS(dmc, &ds)); 9606 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9607 PetscCall(PetscWeakFormClear(wf)); 9608 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9609 PetscCall(DMCreateMatrix(dmc, mass)); 9610 PetscCall(DMGetLocalVector(dmc, &u)); 9611 PetscCall(DMPlexGetDepth(dmc, &depth)); 9612 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9613 PetscCall(MatZeroEntries(*mass)); 9614 key.label = NULL; 9615 key.value = 0; 9616 key.field = 0; 9617 key.part = 0; 9618 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9619 PetscCall(ISDestroy(&cellIS)); 9620 PetscCall(DMRestoreLocalVector(dmc, &u)); 9621 PetscCall(DMDestroy(&dmc)); 9622 } else { 9623 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9624 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9625 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9626 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9627 9628 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9629 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9630 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9631 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9632 9633 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9634 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9635 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9636 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9637 } 9638 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9639 PetscFunctionReturn(0); 9640 } 9641 9642 /*@ 9643 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9644 9645 Input Parameter: 9646 . dm - The DMPlex object 9647 9648 Output Parameter: 9649 . regular - The flag 9650 9651 Level: intermediate 9652 9653 .seealso: `DMPlexSetRegularRefinement()` 9654 @*/ 9655 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9656 { 9657 PetscFunctionBegin; 9658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9659 PetscValidBoolPointer(regular, 2); 9660 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9661 PetscFunctionReturn(0); 9662 } 9663 9664 /*@ 9665 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9666 9667 Input Parameters: 9668 + dm - The DMPlex object 9669 - regular - The flag 9670 9671 Level: intermediate 9672 9673 .seealso: `DMPlexGetRegularRefinement()` 9674 @*/ 9675 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9676 { 9677 PetscFunctionBegin; 9678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9679 ((DM_Plex *)dm->data)->regularRefinement = regular; 9680 PetscFunctionReturn(0); 9681 } 9682 9683 /* anchors */ 9684 /*@ 9685 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9686 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9687 9688 not collective 9689 9690 Input Parameter: 9691 . dm - The DMPlex object 9692 9693 Output Parameters: 9694 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9695 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9696 9697 Level: intermediate 9698 9699 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9700 @*/ 9701 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9702 { 9703 DM_Plex *plex = (DM_Plex *)dm->data; 9704 9705 PetscFunctionBegin; 9706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9707 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9708 if (anchorSection) *anchorSection = plex->anchorSection; 9709 if (anchorIS) *anchorIS = plex->anchorIS; 9710 PetscFunctionReturn(0); 9711 } 9712 9713 /*@ 9714 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9715 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9716 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9717 9718 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9719 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9720 9721 collective on dm 9722 9723 Input Parameters: 9724 + dm - The DMPlex object 9725 . 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). 9726 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9727 9728 The reference counts of anchorSection and anchorIS are incremented. 9729 9730 Level: intermediate 9731 9732 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9733 @*/ 9734 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9735 { 9736 DM_Plex *plex = (DM_Plex *)dm->data; 9737 PetscMPIInt result; 9738 9739 PetscFunctionBegin; 9740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9741 if (anchorSection) { 9742 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9743 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9744 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9745 } 9746 if (anchorIS) { 9747 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9748 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9749 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9750 } 9751 9752 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9753 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9754 plex->anchorSection = anchorSection; 9755 9756 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9757 PetscCall(ISDestroy(&plex->anchorIS)); 9758 plex->anchorIS = anchorIS; 9759 9760 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9761 PetscInt size, a, pStart, pEnd; 9762 const PetscInt *anchors; 9763 9764 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9765 PetscCall(ISGetLocalSize(anchorIS, &size)); 9766 PetscCall(ISGetIndices(anchorIS, &anchors)); 9767 for (a = 0; a < size; a++) { 9768 PetscInt p; 9769 9770 p = anchors[a]; 9771 if (p >= pStart && p < pEnd) { 9772 PetscInt dof; 9773 9774 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9775 if (dof) { 9776 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9777 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9778 } 9779 } 9780 } 9781 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9782 } 9783 /* reset the generic constraints */ 9784 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9785 PetscFunctionReturn(0); 9786 } 9787 9788 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9789 { 9790 PetscSection anchorSection; 9791 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9792 9793 PetscFunctionBegin; 9794 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9795 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9796 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9797 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9798 if (numFields) { 9799 PetscInt f; 9800 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9801 9802 for (f = 0; f < numFields; f++) { 9803 PetscInt numComp; 9804 9805 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9806 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9807 } 9808 } 9809 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9810 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9811 pStart = PetscMax(pStart, sStart); 9812 pEnd = PetscMin(pEnd, sEnd); 9813 pEnd = PetscMax(pStart, pEnd); 9814 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9815 for (p = pStart; p < pEnd; p++) { 9816 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9817 if (dof) { 9818 PetscCall(PetscSectionGetDof(section, p, &dof)); 9819 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9820 for (f = 0; f < numFields; f++) { 9821 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9822 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9823 } 9824 } 9825 } 9826 PetscCall(PetscSectionSetUp(*cSec)); 9827 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9828 PetscFunctionReturn(0); 9829 } 9830 9831 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9832 { 9833 PetscSection aSec; 9834 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9835 const PetscInt *anchors; 9836 PetscInt numFields, f; 9837 IS aIS; 9838 MatType mtype; 9839 PetscBool iscuda, iskokkos; 9840 9841 PetscFunctionBegin; 9842 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9843 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9844 PetscCall(PetscSectionGetStorageSize(section, &n)); 9845 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9846 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9847 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9848 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9849 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9850 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9851 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9852 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9853 else mtype = MATSEQAIJ; 9854 PetscCall(MatSetType(*cMat, mtype)); 9855 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9856 PetscCall(ISGetIndices(aIS, &anchors)); 9857 /* cSec will be a subset of aSec and section */ 9858 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9859 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9860 PetscCall(PetscMalloc1(m + 1, &i)); 9861 i[0] = 0; 9862 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9863 for (p = pStart; p < pEnd; p++) { 9864 PetscInt rDof, rOff, r; 9865 9866 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9867 if (!rDof) continue; 9868 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9869 if (numFields) { 9870 for (f = 0; f < numFields; f++) { 9871 annz = 0; 9872 for (r = 0; r < rDof; r++) { 9873 a = anchors[rOff + r]; 9874 if (a < sStart || a >= sEnd) continue; 9875 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9876 annz += aDof; 9877 } 9878 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9879 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9880 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9881 } 9882 } else { 9883 annz = 0; 9884 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9885 for (q = 0; q < dof; q++) { 9886 a = anchors[rOff + q]; 9887 if (a < sStart || a >= sEnd) continue; 9888 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9889 annz += aDof; 9890 } 9891 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9892 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9893 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9894 } 9895 } 9896 nnz = i[m]; 9897 PetscCall(PetscMalloc1(nnz, &j)); 9898 offset = 0; 9899 for (p = pStart; p < pEnd; p++) { 9900 if (numFields) { 9901 for (f = 0; f < numFields; f++) { 9902 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9903 for (q = 0; q < dof; q++) { 9904 PetscInt rDof, rOff, r; 9905 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9906 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9907 for (r = 0; r < rDof; r++) { 9908 PetscInt s; 9909 9910 a = anchors[rOff + r]; 9911 if (a < sStart || a >= sEnd) continue; 9912 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9913 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9914 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9915 } 9916 } 9917 } 9918 } else { 9919 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9920 for (q = 0; q < dof; q++) { 9921 PetscInt rDof, rOff, r; 9922 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9923 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9924 for (r = 0; r < rDof; r++) { 9925 PetscInt s; 9926 9927 a = anchors[rOff + r]; 9928 if (a < sStart || a >= sEnd) continue; 9929 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9930 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9931 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9932 } 9933 } 9934 } 9935 } 9936 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9937 PetscCall(PetscFree(i)); 9938 PetscCall(PetscFree(j)); 9939 PetscCall(ISRestoreIndices(aIS, &anchors)); 9940 PetscFunctionReturn(0); 9941 } 9942 9943 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9944 { 9945 DM_Plex *plex = (DM_Plex *)dm->data; 9946 PetscSection anchorSection, section, cSec; 9947 Mat cMat; 9948 9949 PetscFunctionBegin; 9950 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9951 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9952 if (anchorSection) { 9953 PetscInt Nf; 9954 9955 PetscCall(DMGetLocalSection(dm, §ion)); 9956 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9957 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9958 PetscCall(DMGetNumFields(dm, &Nf)); 9959 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9960 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9961 PetscCall(PetscSectionDestroy(&cSec)); 9962 PetscCall(MatDestroy(&cMat)); 9963 } 9964 PetscFunctionReturn(0); 9965 } 9966 9967 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9968 { 9969 IS subis; 9970 PetscSection section, subsection; 9971 9972 PetscFunctionBegin; 9973 PetscCall(DMGetLocalSection(dm, §ion)); 9974 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9975 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9976 /* Create subdomain */ 9977 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9978 /* Create submodel */ 9979 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9980 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9981 PetscCall(DMSetLocalSection(*subdm, subsection)); 9982 PetscCall(PetscSectionDestroy(&subsection)); 9983 PetscCall(DMCopyDisc(dm, *subdm)); 9984 /* Create map from submodel to global model */ 9985 if (is) { 9986 PetscSection sectionGlobal, subsectionGlobal; 9987 IS spIS; 9988 const PetscInt *spmap; 9989 PetscInt *subIndices; 9990 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9991 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9992 9993 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9994 PetscCall(ISGetIndices(spIS, &spmap)); 9995 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9996 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9997 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9998 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9999 for (p = pStart; p < pEnd; ++p) { 10000 PetscInt gdof, pSubSize = 0; 10001 10002 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10003 if (gdof > 0) { 10004 for (f = 0; f < Nf; ++f) { 10005 PetscInt fdof, fcdof; 10006 10007 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10008 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10009 pSubSize += fdof - fcdof; 10010 } 10011 subSize += pSubSize; 10012 if (pSubSize) { 10013 if (bs < 0) { 10014 bs = pSubSize; 10015 } else if (bs != pSubSize) { 10016 /* Layout does not admit a pointwise block size */ 10017 bs = 1; 10018 } 10019 } 10020 } 10021 } 10022 /* Must have same blocksize on all procs (some might have no points) */ 10023 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10024 bsLocal[1] = bs; 10025 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10026 if (bsMinMax[0] != bsMinMax[1]) { 10027 bs = 1; 10028 } else { 10029 bs = bsMinMax[0]; 10030 } 10031 PetscCall(PetscMalloc1(subSize, &subIndices)); 10032 for (p = pStart; p < pEnd; ++p) { 10033 PetscInt gdof, goff; 10034 10035 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10036 if (gdof > 0) { 10037 const PetscInt point = spmap[p]; 10038 10039 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10040 for (f = 0; f < Nf; ++f) { 10041 PetscInt fdof, fcdof, fc, f2, poff = 0; 10042 10043 /* Can get rid of this loop by storing field information in the global section */ 10044 for (f2 = 0; f2 < f; ++f2) { 10045 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10046 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10047 poff += fdof - fcdof; 10048 } 10049 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10050 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10051 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10052 } 10053 } 10054 } 10055 PetscCall(ISRestoreIndices(spIS, &spmap)); 10056 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10057 if (bs > 1) { 10058 /* We need to check that the block size does not come from non-contiguous fields */ 10059 PetscInt i, j, set = 1; 10060 for (i = 0; i < subSize; i += bs) { 10061 for (j = 0; j < bs; ++j) { 10062 if (subIndices[i + j] != subIndices[i] + j) { 10063 set = 0; 10064 break; 10065 } 10066 } 10067 } 10068 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10069 } 10070 /* Attach nullspace */ 10071 for (f = 0; f < Nf; ++f) { 10072 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10073 if ((*subdm)->nullspaceConstructors[f]) break; 10074 } 10075 if (f < Nf) { 10076 MatNullSpace nullSpace; 10077 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10078 10079 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10080 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10081 } 10082 } 10083 PetscFunctionReturn(0); 10084 } 10085 10086 /*@ 10087 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10088 10089 Input Parameter: 10090 - dm - The DM 10091 10092 Level: developer 10093 10094 Options Database Keys: 10095 . -dm_plex_monitor_throughput - Activate the monitor 10096 10097 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 10098 @*/ 10099 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10100 { 10101 #if defined(PETSC_USE_LOG) 10102 PetscStageLog stageLog; 10103 PetscLogEvent event; 10104 PetscLogStage stage; 10105 PetscEventPerfInfo eventInfo; 10106 PetscReal cellRate, flopRate; 10107 PetscInt cStart, cEnd, Nf, N; 10108 const char *name; 10109 #endif 10110 10111 PetscFunctionBegin; 10112 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10113 #if defined(PETSC_USE_LOG) 10114 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10115 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10116 PetscCall(DMGetNumFields(dm, &Nf)); 10117 PetscCall(PetscLogGetStageLog(&stageLog)); 10118 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 10119 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10120 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 10121 N = (cEnd - cStart) * Nf * eventInfo.count; 10122 flopRate = eventInfo.flops / eventInfo.time; 10123 cellRate = N / eventInfo.time; 10124 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DM (%s) FE Residual Integration: %" PetscInt_FMT " 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))); 10125 #else 10126 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 10127 #endif 10128 PetscFunctionReturn(0); 10129 } 10130