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, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal"" cells 74 75 Level: developer 76 77 Note: 78 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 85 PetscInt cS, cE, c; 86 87 PetscFunctionBegin; 88 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 89 for (c = cS; c < cE; ++c) { 90 DMPolytopeType cct; 91 92 PetscCall(DMPlexGetCellType(dm, c, &cct)); 93 if ((PetscInt)cct < 0) break; 94 switch (cct) { 95 case DM_POLYTOPE_POINT: 96 case DM_POLYTOPE_SEGMENT: 97 case DM_POLYTOPE_TRIANGLE: 98 case DM_POLYTOPE_QUADRILATERAL: 99 case DM_POLYTOPE_TETRAHEDRON: 100 case DM_POLYTOPE_HEXAHEDRON: 101 ct = cct; 102 break; 103 default: 104 break; 105 } 106 if (ct != DM_POLYTOPE_UNKNOWN) break; 107 } 108 if (ct != DM_POLYTOPE_UNKNOWN) { 109 DMLabel ctLabel; 110 111 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 112 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 113 // Reset label for fast lookup 114 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 115 } 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 124 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 125 126 PetscFunctionBegin; 127 *ft = PETSC_VTK_INVALID; 128 PetscCall(DMGetCoordinateDim(dm, &cdim)); 129 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 130 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 131 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 132 if (field >= 0) { 133 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 134 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 135 } else { 136 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 137 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 138 } 139 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 140 if (globalvcdof[0]) { 141 *sStart = vStart; 142 *sEnd = vEnd; 143 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 144 else *ft = PETSC_VTK_POINT_FIELD; 145 } else if (globalvcdof[1]) { 146 *sStart = cStart; 147 *sEnd = cEnd; 148 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 149 else *ft = PETSC_VTK_CELL_FIELD; 150 } else { 151 if (field >= 0) { 152 const char *fieldname; 153 154 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 155 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 156 } else { 157 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 158 } 159 } 160 PetscFunctionReturn(PETSC_SUCCESS); 161 } 162 163 /*@ 164 DMPlexVecView1D - Plot many 1D solutions on the same line graph 165 166 Collective 167 168 Input Parameters: 169 + dm - The `DMPLEX` object 170 . n - The number of vectors 171 . u - The array of local vectors 172 - viewer - The `PetscViewer` 173 174 Level: advanced 175 176 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 177 @*/ 178 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 179 { 180 PetscDS ds; 181 PetscDraw draw = NULL; 182 PetscDrawLG lg; 183 Vec coordinates; 184 const PetscScalar *coords, **sol; 185 PetscReal *vals; 186 PetscInt *Nc; 187 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 188 char **names; 189 190 PetscFunctionBegin; 191 PetscCall(DMGetDS(dm, &ds)); 192 PetscCall(PetscDSGetNumFields(ds, &Nf)); 193 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 194 PetscCall(PetscDSGetComponents(ds, &Nc)); 195 196 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 197 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 198 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 199 200 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 201 for (i = 0, l = 0; i < n; ++i) { 202 const char *vname; 203 204 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 205 for (f = 0; f < Nf; ++f) { 206 PetscObject disc; 207 const char *fname; 208 char tmpname[PETSC_MAX_PATH_LEN]; 209 210 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 211 /* TODO Create names for components */ 212 for (c = 0; c < Nc[f]; ++c, ++l) { 213 PetscCall(PetscObjectGetName(disc, &fname)); 214 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 215 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 216 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 217 PetscCall(PetscStrallocpy(tmpname, &names[l])); 218 } 219 } 220 } 221 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 222 /* Just add P_1 support for now */ 223 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 224 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 225 PetscCall(VecGetArrayRead(coordinates, &coords)); 226 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 227 for (v = vStart; v < vEnd; ++v) { 228 PetscScalar *x, *svals; 229 230 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 231 for (i = 0; i < n; ++i) { 232 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 233 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 234 } 235 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 236 } 237 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 238 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 239 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 240 PetscCall(PetscFree3(sol, names, vals)); 241 242 PetscCall(PetscDrawLGDraw(lg)); 243 PetscCall(PetscDrawLGDestroy(&lg)); 244 PetscFunctionReturn(PETSC_SUCCESS); 245 } 246 247 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 248 { 249 DM dm; 250 251 PetscFunctionBegin; 252 PetscCall(VecGetDM(u, &dm)); 253 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 258 { 259 DM dm; 260 PetscSection s; 261 PetscDraw draw, popup; 262 DM cdm; 263 PetscSection coordSection; 264 Vec coordinates; 265 const PetscScalar *array; 266 PetscReal lbound[3], ubound[3]; 267 PetscReal vbound[2], time; 268 PetscBool flg; 269 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 270 const char *name; 271 char title[PETSC_MAX_PATH_LEN]; 272 273 PetscFunctionBegin; 274 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 275 PetscCall(VecGetDM(v, &dm)); 276 PetscCall(DMGetCoordinateDim(dm, &dim)); 277 PetscCall(DMGetLocalSection(dm, &s)); 278 PetscCall(PetscSectionGetNumFields(s, &Nf)); 279 PetscCall(DMGetCoarsenLevel(dm, &level)); 280 PetscCall(DMGetCoordinateDM(dm, &cdm)); 281 PetscCall(DMGetLocalSection(cdm, &coordSection)); 282 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 283 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 284 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 285 286 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 287 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 288 289 PetscCall(VecGetLocalSize(coordinates, &N)); 290 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 291 PetscCall(PetscDrawClear(draw)); 292 293 /* Could implement something like DMDASelectFields() */ 294 for (f = 0; f < Nf; ++f) { 295 DM fdm = dm; 296 Vec fv = v; 297 IS fis; 298 char prefix[PETSC_MAX_PATH_LEN]; 299 const char *fname; 300 301 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 302 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 303 304 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 305 else prefix[0] = '\0'; 306 if (Nf > 1) { 307 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 308 PetscCall(VecGetSubVector(v, fis, &fv)); 309 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 310 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 311 } 312 for (comp = 0; comp < Nc; ++comp, ++w) { 313 PetscInt nmax = 2; 314 315 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 316 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 317 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 318 PetscCall(PetscDrawSetTitle(draw, title)); 319 320 /* TODO Get max and min only for this component */ 321 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 322 if (!flg) { 323 PetscCall(VecMin(fv, NULL, &vbound[0])); 324 PetscCall(VecMax(fv, NULL, &vbound[1])); 325 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 326 } 327 328 PetscCall(PetscDrawGetPopup(draw, &popup)); 329 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 330 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 331 PetscCall(VecGetArrayRead(fv, &array)); 332 for (c = cStart; c < cEnd; ++c) { 333 PetscScalar *coords = NULL, *a = NULL; 334 const PetscScalar *coords_arr; 335 PetscBool isDG; 336 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 337 338 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 339 if (a) { 340 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 341 color[1] = color[2] = color[3] = color[0]; 342 } else { 343 PetscScalar *vals = NULL; 344 PetscInt numVals, va; 345 346 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 347 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); 348 switch (numVals / Nc) { 349 case 3: /* P1 Triangle */ 350 case 4: /* P1 Quadrangle */ 351 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 352 break; 353 case 6: /* P2 Triangle */ 354 case 8: /* P2 Quadrangle */ 355 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 356 break; 357 default: 358 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 359 } 360 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 361 } 362 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 363 switch (numCoords) { 364 case 6: 365 case 12: /* Localized triangle */ 366 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])); 367 break; 368 case 8: 369 case 16: /* Localized quadrilateral */ 370 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])); 371 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])); 372 break; 373 default: 374 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 375 } 376 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 377 } 378 PetscCall(VecRestoreArrayRead(fv, &array)); 379 PetscCall(PetscDrawFlush(draw)); 380 PetscCall(PetscDrawPause(draw)); 381 PetscCall(PetscDrawSave(draw)); 382 } 383 if (Nf > 1) { 384 PetscCall(VecRestoreSubVector(v, fis, &fv)); 385 PetscCall(ISDestroy(&fis)); 386 PetscCall(DMDestroy(&fdm)); 387 } 388 } 389 PetscFunctionReturn(PETSC_SUCCESS); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 393 { 394 DM dm; 395 PetscDraw draw; 396 PetscInt dim; 397 PetscBool isnull; 398 399 PetscFunctionBegin; 400 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 401 PetscCall(PetscDrawIsNull(draw, &isnull)); 402 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 403 404 PetscCall(VecGetDM(v, &dm)); 405 PetscCall(DMGetCoordinateDim(dm, &dim)); 406 switch (dim) { 407 case 1: 408 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 409 break; 410 case 2: 411 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 412 break; 413 default: 414 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 415 } 416 PetscFunctionReturn(PETSC_SUCCESS); 417 } 418 419 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 420 { 421 DM dm; 422 Vec locv; 423 const char *name; 424 PetscSection section; 425 PetscInt pStart, pEnd; 426 PetscInt numFields; 427 PetscViewerVTKFieldType ft; 428 429 PetscFunctionBegin; 430 PetscCall(VecGetDM(v, &dm)); 431 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 432 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 433 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 434 PetscCall(VecCopy(v, locv)); 435 PetscCall(DMGetLocalSection(dm, §ion)); 436 PetscCall(PetscSectionGetNumFields(section, &numFields)); 437 if (!numFields) { 438 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 439 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 440 } else { 441 PetscInt f; 442 443 for (f = 0; f < numFields; f++) { 444 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 445 if (ft == PETSC_VTK_INVALID) continue; 446 PetscCall(PetscObjectReference((PetscObject)locv)); 447 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 448 } 449 PetscCall(VecDestroy(&locv)); 450 } 451 PetscFunctionReturn(PETSC_SUCCESS); 452 } 453 454 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 455 { 456 DM dm; 457 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 458 459 PetscFunctionBegin; 460 PetscCall(VecGetDM(v, &dm)); 461 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 462 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 463 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 464 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 465 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 466 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 467 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 468 PetscInt i, numFields; 469 PetscObject fe; 470 PetscBool fem = PETSC_FALSE; 471 Vec locv = v; 472 const char *name; 473 PetscInt step; 474 PetscReal time; 475 476 PetscCall(DMGetNumFields(dm, &numFields)); 477 for (i = 0; i < numFields; i++) { 478 PetscCall(DMGetField(dm, i, NULL, &fe)); 479 if (fe->classid == PETSCFE_CLASSID) { 480 fem = PETSC_TRUE; 481 break; 482 } 483 } 484 if (fem) { 485 PetscObject isZero; 486 487 PetscCall(DMGetLocalVector(dm, &locv)); 488 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 489 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 490 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 491 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 492 PetscCall(VecCopy(v, locv)); 493 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 494 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 495 } 496 if (isvtk) { 497 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 498 } else if (ishdf5) { 499 #if defined(PETSC_HAVE_HDF5) 500 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 501 #else 502 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 503 #endif 504 } else if (isdraw) { 505 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 506 } else if (isglvis) { 507 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 508 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 509 PetscCall(VecView_GLVis(locv, viewer)); 510 } else if (iscgns) { 511 #if defined(PETSC_HAVE_CGNS) 512 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 513 #else 514 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 515 #endif 516 } 517 if (fem) { 518 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 519 PetscCall(DMRestoreLocalVector(dm, &locv)); 520 } 521 } else { 522 PetscBool isseq; 523 524 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 525 if (isseq) PetscCall(VecView_Seq(v, viewer)); 526 else PetscCall(VecView_MPI(v, viewer)); 527 } 528 PetscFunctionReturn(PETSC_SUCCESS); 529 } 530 531 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 532 { 533 DM dm; 534 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 535 536 PetscFunctionBegin; 537 PetscCall(VecGetDM(v, &dm)); 538 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 539 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 540 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 541 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 542 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 543 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 544 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 545 if (isvtk || isdraw || isglvis || iscgns) { 546 Vec locv; 547 PetscObject isZero; 548 const char *name; 549 550 PetscCall(DMGetLocalVector(dm, &locv)); 551 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 552 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 553 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 554 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 555 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 556 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 557 PetscCall(VecView_Plex_Local(locv, viewer)); 558 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 559 PetscCall(DMRestoreLocalVector(dm, &locv)); 560 } else if (ishdf5) { 561 #if defined(PETSC_HAVE_HDF5) 562 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 563 #else 564 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 565 #endif 566 } else if (isexodusii) { 567 #if defined(PETSC_HAVE_EXODUSII) 568 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 569 #else 570 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 571 #endif 572 } else { 573 PetscBool isseq; 574 575 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 576 if (isseq) PetscCall(VecView_Seq(v, viewer)); 577 else PetscCall(VecView_MPI(v, viewer)); 578 } 579 PetscFunctionReturn(PETSC_SUCCESS); 580 } 581 582 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 583 { 584 DM dm; 585 MPI_Comm comm; 586 PetscViewerFormat format; 587 Vec v; 588 PetscBool isvtk, ishdf5; 589 590 PetscFunctionBegin; 591 PetscCall(VecGetDM(originalv, &dm)); 592 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 593 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 594 PetscCall(PetscViewerGetFormat(viewer, &format)); 595 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 596 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 597 if (format == PETSC_VIEWER_NATIVE) { 598 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 599 /* this need a better fix */ 600 if (dm->useNatural) { 601 if (dm->sfNatural) { 602 const char *vecname; 603 PetscInt n, nroots; 604 605 PetscCall(VecGetLocalSize(originalv, &n)); 606 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 607 if (n == nroots) { 608 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 609 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 610 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 611 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 612 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 613 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 614 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 615 } else v = originalv; 616 } else v = originalv; 617 618 if (ishdf5) { 619 #if defined(PETSC_HAVE_HDF5) 620 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 621 #else 622 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 623 #endif 624 } else if (isvtk) { 625 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 626 } else { 627 PetscBool isseq; 628 629 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 630 if (isseq) PetscCall(VecView_Seq(v, viewer)); 631 else PetscCall(VecView_MPI(v, viewer)); 632 } 633 if (v != originalv) PetscCall(VecDestroy(&v)); 634 PetscFunctionReturn(PETSC_SUCCESS); 635 } 636 637 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 638 { 639 DM dm; 640 PetscBool ishdf5; 641 642 PetscFunctionBegin; 643 PetscCall(VecGetDM(v, &dm)); 644 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 645 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 646 if (ishdf5) { 647 DM dmBC; 648 Vec gv; 649 const char *name; 650 651 PetscCall(DMGetOutputDM(dm, &dmBC)); 652 PetscCall(DMGetGlobalVector(dmBC, &gv)); 653 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 654 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 655 PetscCall(VecLoad_Default(gv, viewer)); 656 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 657 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 658 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 659 } else PetscCall(VecLoad_Default(v, viewer)); 660 PetscFunctionReturn(PETSC_SUCCESS); 661 } 662 663 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 664 { 665 DM dm; 666 PetscBool ishdf5, isexodusii; 667 668 PetscFunctionBegin; 669 PetscCall(VecGetDM(v, &dm)); 670 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 671 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 672 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 673 if (ishdf5) { 674 #if defined(PETSC_HAVE_HDF5) 675 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 676 #else 677 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 678 #endif 679 } else if (isexodusii) { 680 #if defined(PETSC_HAVE_EXODUSII) 681 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 682 #else 683 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 684 #endif 685 } else PetscCall(VecLoad_Default(v, viewer)); 686 PetscFunctionReturn(PETSC_SUCCESS); 687 } 688 689 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 690 { 691 DM dm; 692 PetscViewerFormat format; 693 PetscBool ishdf5; 694 695 PetscFunctionBegin; 696 PetscCall(VecGetDM(originalv, &dm)); 697 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 698 PetscCall(PetscViewerGetFormat(viewer, &format)); 699 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 700 if (format == PETSC_VIEWER_NATIVE) { 701 if (dm->useNatural) { 702 if (dm->sfNatural) { 703 if (ishdf5) { 704 #if defined(PETSC_HAVE_HDF5) 705 Vec v; 706 const char *vecname; 707 708 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 709 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 710 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 711 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 712 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 713 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 714 PetscCall(VecDestroy(&v)); 715 #else 716 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 717 #endif 718 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 719 } 720 } else PetscCall(VecLoad_Default(originalv, viewer)); 721 } 722 PetscFunctionReturn(PETSC_SUCCESS); 723 } 724 725 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 726 { 727 PetscSection coordSection; 728 Vec coordinates; 729 DMLabel depthLabel, celltypeLabel; 730 const char *name[4]; 731 const PetscScalar *a; 732 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 733 734 PetscFunctionBegin; 735 PetscCall(DMGetDimension(dm, &dim)); 736 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 737 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 738 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 739 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 740 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 741 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 742 PetscCall(VecGetArrayRead(coordinates, &a)); 743 name[0] = "vertex"; 744 name[1] = "edge"; 745 name[dim - 1] = "face"; 746 name[dim] = "cell"; 747 for (c = cStart; c < cEnd; ++c) { 748 PetscInt *closure = NULL; 749 PetscInt closureSize, cl, ct; 750 751 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 752 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 753 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 754 PetscCall(PetscViewerASCIIPushTab(viewer)); 755 for (cl = 0; cl < closureSize * 2; cl += 2) { 756 PetscInt point = closure[cl], depth, dof, off, d, p; 757 758 if ((point < pStart) || (point >= pEnd)) continue; 759 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 760 if (!dof) continue; 761 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 762 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 763 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 764 for (p = 0; p < dof / dim; ++p) { 765 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 766 for (d = 0; d < dim; ++d) { 767 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 768 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 769 } 770 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 771 } 772 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 773 } 774 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 775 PetscCall(PetscViewerASCIIPopTab(viewer)); 776 } 777 PetscCall(VecRestoreArrayRead(coordinates, &a)); 778 PetscFunctionReturn(PETSC_SUCCESS); 779 } 780 781 typedef enum { 782 CS_CARTESIAN, 783 CS_POLAR, 784 CS_CYLINDRICAL, 785 CS_SPHERICAL 786 } CoordSystem; 787 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 788 789 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 790 { 791 PetscInt i; 792 793 PetscFunctionBegin; 794 if (dim > 3) { 795 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 796 } else { 797 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 798 799 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 800 switch (cs) { 801 case CS_CARTESIAN: 802 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 803 break; 804 case CS_POLAR: 805 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 806 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 807 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 808 break; 809 case CS_CYLINDRICAL: 810 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 811 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 812 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 813 trcoords[2] = coords[2]; 814 break; 815 case CS_SPHERICAL: 816 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 817 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 818 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 819 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 820 break; 821 } 822 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 823 } 824 PetscFunctionReturn(PETSC_SUCCESS); 825 } 826 827 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 828 { 829 DM_Plex *mesh = (DM_Plex *)dm->data; 830 DM cdm, cdmCell; 831 PetscSection coordSection, coordSectionCell; 832 Vec coordinates, coordinatesCell; 833 PetscViewerFormat format; 834 835 PetscFunctionBegin; 836 PetscCall(PetscViewerGetFormat(viewer, &format)); 837 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 838 const char *name; 839 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 840 PetscInt pStart, pEnd, p, numLabels, l; 841 PetscMPIInt rank, size; 842 843 PetscCall(DMGetCoordinateDM(dm, &cdm)); 844 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 845 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 846 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 847 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 848 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 849 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 850 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 851 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 852 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 853 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 854 PetscCall(DMGetDimension(dm, &dim)); 855 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 856 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 857 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 858 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 859 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 860 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 861 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 862 for (p = pStart; p < pEnd; ++p) { 863 PetscInt dof, off, s; 864 865 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 866 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 867 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 868 } 869 PetscCall(PetscViewerFlush(viewer)); 870 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 871 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 872 for (p = pStart; p < pEnd; ++p) { 873 PetscInt dof, off, c; 874 875 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 876 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 877 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])); 878 } 879 PetscCall(PetscViewerFlush(viewer)); 880 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 881 if (coordSection && coordinates) { 882 CoordSystem cs = CS_CARTESIAN; 883 const PetscScalar *array, *arrayCell = NULL; 884 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 885 PetscMPIInt rank; 886 const char *name; 887 888 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 889 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 890 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 891 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 892 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 893 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 894 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 895 pStart = PetscMin(pvStart, pcStart); 896 pEnd = PetscMax(pvEnd, pcEnd); 897 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 898 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 899 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 900 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 901 902 PetscCall(VecGetArrayRead(coordinates, &array)); 903 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 904 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 905 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 906 for (p = pStart; p < pEnd; ++p) { 907 PetscInt dof, off; 908 909 if (p >= pvStart && p < pvEnd) { 910 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 911 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 912 if (dof) { 913 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 914 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 915 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 916 } 917 } 918 if (cdmCell && p >= pcStart && p < pcEnd) { 919 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 920 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 921 if (dof) { 922 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 923 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 924 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 925 } 926 } 927 } 928 PetscCall(PetscViewerFlush(viewer)); 929 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 930 PetscCall(VecRestoreArrayRead(coordinates, &array)); 931 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 932 } 933 PetscCall(DMGetNumLabels(dm, &numLabels)); 934 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 935 for (l = 0; l < numLabels; ++l) { 936 DMLabel label; 937 PetscBool isdepth; 938 const char *name; 939 940 PetscCall(DMGetLabelName(dm, l, &name)); 941 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 942 if (isdepth) continue; 943 PetscCall(DMGetLabel(dm, name, &label)); 944 PetscCall(DMLabelView(label, viewer)); 945 } 946 if (size > 1) { 947 PetscSF sf; 948 949 PetscCall(DMGetPointSF(dm, &sf)); 950 PetscCall(PetscSFView(sf, viewer)); 951 } 952 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 953 PetscCall(PetscViewerFlush(viewer)); 954 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 955 const char *name, *color; 956 const char *defcolors[3] = {"gray", "orange", "green"}; 957 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 958 char lname[PETSC_MAX_PATH_LEN]; 959 PetscReal scale = 2.0; 960 PetscReal tikzscale = 1.0; 961 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 962 double tcoords[3]; 963 PetscScalar *coords; 964 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 965 PetscMPIInt rank, size; 966 char **names, **colors, **lcolors; 967 PetscBool flg, lflg; 968 PetscBT wp = NULL; 969 PetscInt pEnd, pStart; 970 971 PetscCall(DMGetCoordinateDM(dm, &cdm)); 972 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 973 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 974 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 975 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 976 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 977 PetscCall(DMGetDimension(dm, &dim)); 978 PetscCall(DMPlexGetDepth(dm, &depth)); 979 PetscCall(DMGetNumLabels(dm, &numLabels)); 980 numLabels = PetscMax(numLabels, 10); 981 numColors = 10; 982 numLColors = 10; 983 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 984 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 985 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 986 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 987 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 988 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 989 n = 4; 990 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 991 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 992 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 993 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 994 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 995 if (!useLabels) numLabels = 0; 996 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 997 if (!useColors) { 998 numColors = 3; 999 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1000 } 1001 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1002 if (!useColors) { 1003 numLColors = 4; 1004 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1005 } 1006 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1007 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1008 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1009 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1010 if (depth < dim) plotEdges = PETSC_FALSE; 1011 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1012 1013 /* filter points with labelvalue != labeldefaultvalue */ 1014 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1015 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1016 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1017 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1018 if (lflg) { 1019 DMLabel lbl; 1020 1021 PetscCall(DMGetLabel(dm, lname, &lbl)); 1022 if (lbl) { 1023 PetscInt val, defval; 1024 1025 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1026 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1027 for (c = pStart; c < pEnd; c++) { 1028 PetscInt *closure = NULL; 1029 PetscInt closureSize; 1030 1031 PetscCall(DMLabelGetValue(lbl, c, &val)); 1032 if (val == defval) continue; 1033 1034 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1035 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1036 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1037 } 1038 } 1039 } 1040 1041 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1042 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1043 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1044 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1045 \\documentclass[tikz]{standalone}\n\n\ 1046 \\usepackage{pgflibraryshapes}\n\ 1047 \\usetikzlibrary{backgrounds}\n\ 1048 \\usetikzlibrary{arrows}\n\ 1049 \\begin{document}\n")); 1050 if (size > 1) { 1051 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1052 for (p = 0; p < size; ++p) { 1053 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1055 } 1056 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1057 } 1058 if (drawHasse) { 1059 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1060 1061 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1062 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1063 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1064 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1065 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1066 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1067 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1068 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1069 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1070 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1071 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1072 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1073 } 1074 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1075 1076 /* Plot vertices */ 1077 PetscCall(VecGetArray(coordinates, &coords)); 1078 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1079 for (v = vStart; v < vEnd; ++v) { 1080 PetscInt off, dof, d; 1081 PetscBool isLabeled = PETSC_FALSE; 1082 1083 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1084 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1085 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1086 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1087 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1088 for (d = 0; d < dof; ++d) { 1089 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1090 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1091 } 1092 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1093 if (dim == 3) { 1094 PetscReal tmp = tcoords[1]; 1095 tcoords[1] = tcoords[2]; 1096 tcoords[2] = -tmp; 1097 } 1098 for (d = 0; d < dof; ++d) { 1099 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1100 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1101 } 1102 if (drawHasse) color = colors[0 % numColors]; 1103 else color = colors[rank % numColors]; 1104 for (l = 0; l < numLabels; ++l) { 1105 PetscInt val; 1106 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1107 if (val >= 0) { 1108 color = lcolors[l % numLColors]; 1109 isLabeled = PETSC_TRUE; 1110 break; 1111 } 1112 } 1113 if (drawNumbers[0]) { 1114 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1115 } else if (drawColors[0]) { 1116 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1117 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1118 } 1119 PetscCall(VecRestoreArray(coordinates, &coords)); 1120 PetscCall(PetscViewerFlush(viewer)); 1121 /* Plot edges */ 1122 if (plotEdges) { 1123 PetscCall(VecGetArray(coordinates, &coords)); 1124 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1125 for (e = eStart; e < eEnd; ++e) { 1126 const PetscInt *cone; 1127 PetscInt coneSize, offA, offB, dof, d; 1128 1129 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1130 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1131 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1132 PetscCall(DMPlexGetCone(dm, e, &cone)); 1133 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1134 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1135 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1136 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1137 for (d = 0; d < dof; ++d) { 1138 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1139 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1140 } 1141 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1142 if (dim == 3) { 1143 PetscReal tmp = tcoords[1]; 1144 tcoords[1] = tcoords[2]; 1145 tcoords[2] = -tmp; 1146 } 1147 for (d = 0; d < dof; ++d) { 1148 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1149 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1150 } 1151 if (drawHasse) color = colors[1 % numColors]; 1152 else color = colors[rank % numColors]; 1153 for (l = 0; l < numLabels; ++l) { 1154 PetscInt val; 1155 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1156 if (val >= 0) { 1157 color = lcolors[l % numLColors]; 1158 break; 1159 } 1160 } 1161 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1162 } 1163 PetscCall(VecRestoreArray(coordinates, &coords)); 1164 PetscCall(PetscViewerFlush(viewer)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1166 } 1167 /* Plot cells */ 1168 if (dim == 3 || !drawNumbers[1]) { 1169 for (e = eStart; e < eEnd; ++e) { 1170 const PetscInt *cone; 1171 1172 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1173 color = colors[rank % numColors]; 1174 for (l = 0; l < numLabels; ++l) { 1175 PetscInt val; 1176 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1177 if (val >= 0) { 1178 color = lcolors[l % numLColors]; 1179 break; 1180 } 1181 } 1182 PetscCall(DMPlexGetCone(dm, e, &cone)); 1183 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1184 } 1185 } else { 1186 DMPolytopeType ct; 1187 1188 /* Drawing a 2D polygon */ 1189 for (c = cStart; c < cEnd; ++c) { 1190 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1191 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1192 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1193 const PetscInt *cone; 1194 PetscInt coneSize, e; 1195 1196 PetscCall(DMPlexGetCone(dm, c, &cone)); 1197 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1198 for (e = 0; e < coneSize; ++e) { 1199 const PetscInt *econe; 1200 1201 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1202 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)); 1203 } 1204 } else { 1205 PetscInt *closure = NULL; 1206 PetscInt closureSize, Nv = 0, v; 1207 1208 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1209 for (p = 0; p < closureSize * 2; p += 2) { 1210 const PetscInt point = closure[p]; 1211 1212 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1213 } 1214 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1215 for (v = 0; v <= Nv; ++v) { 1216 const PetscInt vertex = closure[v % Nv]; 1217 1218 if (v > 0) { 1219 if (plotEdges) { 1220 const PetscInt *edge; 1221 PetscInt endpoints[2], ne; 1222 1223 endpoints[0] = closure[v - 1]; 1224 endpoints[1] = vertex; 1225 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1226 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1227 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1228 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1229 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1230 } 1231 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1232 } 1233 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1234 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1235 } 1236 } 1237 } 1238 for (c = cStart; c < cEnd; ++c) { 1239 double ccoords[3] = {0.0, 0.0, 0.0}; 1240 PetscBool isLabeled = PETSC_FALSE; 1241 PetscScalar *cellCoords = NULL; 1242 const PetscScalar *array; 1243 PetscInt numCoords, cdim, d; 1244 PetscBool isDG; 1245 1246 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1247 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1248 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1249 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1250 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1251 for (p = 0; p < numCoords / cdim; ++p) { 1252 for (d = 0; d < cdim; ++d) { 1253 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1254 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1255 } 1256 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1257 if (cdim == 3) { 1258 PetscReal tmp = tcoords[1]; 1259 tcoords[1] = tcoords[2]; 1260 tcoords[2] = -tmp; 1261 } 1262 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1263 } 1264 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1265 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1266 for (d = 0; d < cdim; ++d) { 1267 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1268 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1269 } 1270 if (drawHasse) color = colors[depth % numColors]; 1271 else color = colors[rank % numColors]; 1272 for (l = 0; l < numLabels; ++l) { 1273 PetscInt val; 1274 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1275 if (val >= 0) { 1276 color = lcolors[l % numLColors]; 1277 isLabeled = PETSC_TRUE; 1278 break; 1279 } 1280 } 1281 if (drawNumbers[dim]) { 1282 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1283 } else if (drawColors[dim]) { 1284 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1285 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1286 } 1287 if (drawHasse) { 1288 color = colors[depth % numColors]; 1289 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1290 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1291 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1292 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1293 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1294 1295 color = colors[1 % numColors]; 1296 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1297 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1298 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1299 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1300 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1301 1302 color = colors[0 % numColors]; 1303 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1304 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1305 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1306 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1307 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1308 1309 for (p = pStart; p < pEnd; ++p) { 1310 const PetscInt *cone; 1311 PetscInt coneSize, cp; 1312 1313 PetscCall(DMPlexGetCone(dm, p, &cone)); 1314 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1315 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1316 } 1317 } 1318 PetscCall(PetscViewerFlush(viewer)); 1319 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1320 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1321 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1322 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1323 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1324 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1325 PetscCall(PetscFree3(names, colors, lcolors)); 1326 PetscCall(PetscBTDestroy(&wp)); 1327 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1328 Vec cown, acown; 1329 VecScatter sct; 1330 ISLocalToGlobalMapping g2l; 1331 IS gid, acis; 1332 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1333 MPI_Group ggroup, ngroup; 1334 PetscScalar *array, nid; 1335 const PetscInt *idxs; 1336 PetscInt *idxs2, *start, *adjacency, *work; 1337 PetscInt64 lm[3], gm[3]; 1338 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1339 PetscMPIInt d1, d2, rank; 1340 1341 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1342 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1343 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1344 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1345 #endif 1346 if (ncomm != MPI_COMM_NULL) { 1347 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1348 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1349 d1 = 0; 1350 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1351 nid = d2; 1352 PetscCallMPI(MPI_Group_free(&ggroup)); 1353 PetscCallMPI(MPI_Group_free(&ngroup)); 1354 PetscCallMPI(MPI_Comm_free(&ncomm)); 1355 } else nid = 0.0; 1356 1357 /* Get connectivity */ 1358 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1359 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1360 1361 /* filter overlapped local cells */ 1362 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1363 PetscCall(ISGetIndices(gid, &idxs)); 1364 PetscCall(ISGetLocalSize(gid, &cum)); 1365 PetscCall(PetscMalloc1(cum, &idxs2)); 1366 for (c = cStart, cum = 0; c < cEnd; c++) { 1367 if (idxs[c - cStart] < 0) continue; 1368 idxs2[cum++] = idxs[c - cStart]; 1369 } 1370 PetscCall(ISRestoreIndices(gid, &idxs)); 1371 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1372 PetscCall(ISDestroy(&gid)); 1373 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1374 1375 /* support for node-aware cell locality */ 1376 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1377 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1378 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1379 PetscCall(VecGetArray(cown, &array)); 1380 for (c = 0; c < numVertices; c++) array[c] = nid; 1381 PetscCall(VecRestoreArray(cown, &array)); 1382 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1383 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1384 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1385 PetscCall(ISDestroy(&acis)); 1386 PetscCall(VecScatterDestroy(&sct)); 1387 PetscCall(VecDestroy(&cown)); 1388 1389 /* compute edgeCut */ 1390 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1391 PetscCall(PetscMalloc1(cum, &work)); 1392 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1393 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1394 PetscCall(ISDestroy(&gid)); 1395 PetscCall(VecGetArray(acown, &array)); 1396 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1397 PetscInt totl; 1398 1399 totl = start[c + 1] - start[c]; 1400 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1401 for (i = 0; i < totl; i++) { 1402 if (work[i] < 0) { 1403 ect += 1; 1404 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1405 } 1406 } 1407 } 1408 PetscCall(PetscFree(work)); 1409 PetscCall(VecRestoreArray(acown, &array)); 1410 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1411 lm[1] = -numVertices; 1412 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1413 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1414 lm[0] = ect; /* edgeCut */ 1415 lm[1] = ectn; /* node-aware edgeCut */ 1416 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1417 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1418 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1419 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1420 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1421 #else 1422 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1423 #endif 1424 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1425 PetscCall(PetscFree(start)); 1426 PetscCall(PetscFree(adjacency)); 1427 PetscCall(VecDestroy(&acown)); 1428 } else { 1429 const char *name; 1430 PetscInt *sizes, *hybsizes, *ghostsizes; 1431 PetscInt locDepth, depth, cellHeight, dim, d; 1432 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1433 PetscInt numLabels, l, maxSize = 17; 1434 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1435 MPI_Comm comm; 1436 PetscMPIInt size, rank; 1437 1438 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1439 PetscCallMPI(MPI_Comm_size(comm, &size)); 1440 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1441 PetscCall(DMGetDimension(dm, &dim)); 1442 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1443 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1444 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1445 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1446 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1447 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1448 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1449 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1450 gcNum = gcEnd - gcStart; 1451 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1452 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1453 for (d = 0; d <= depth; d++) { 1454 PetscInt Nc[2] = {0, 0}, ict; 1455 1456 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1457 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1458 ict = ct0; 1459 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1460 ct0 = (DMPolytopeType)ict; 1461 for (p = pStart; p < pEnd; ++p) { 1462 DMPolytopeType ct; 1463 1464 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1465 if (ct == ct0) ++Nc[0]; 1466 else ++Nc[1]; 1467 } 1468 if (size < maxSize) { 1469 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1470 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1471 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1472 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1473 for (p = 0; p < size; ++p) { 1474 if (rank == 0) { 1475 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1476 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1477 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1478 } 1479 } 1480 } else { 1481 PetscInt locMinMax[2]; 1482 1483 locMinMax[0] = Nc[0] + Nc[1]; 1484 locMinMax[1] = Nc[0] + Nc[1]; 1485 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1486 locMinMax[0] = Nc[1]; 1487 locMinMax[1] = Nc[1]; 1488 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1489 if (d == depth) { 1490 locMinMax[0] = gcNum; 1491 locMinMax[1] = gcNum; 1492 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1493 } 1494 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1495 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1496 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1497 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1498 } 1499 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1500 } 1501 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1502 { 1503 const PetscReal *maxCell; 1504 const PetscReal *L; 1505 PetscBool localized; 1506 1507 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1508 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1509 if (L || localized) { 1510 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1511 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1512 if (L) { 1513 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1514 for (d = 0; d < dim; ++d) { 1515 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1516 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1517 } 1518 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1519 } 1520 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1521 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1522 } 1523 } 1524 PetscCall(DMGetNumLabels(dm, &numLabels)); 1525 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1526 for (l = 0; l < numLabels; ++l) { 1527 DMLabel label; 1528 const char *name; 1529 IS valueIS; 1530 const PetscInt *values; 1531 PetscInt numValues, v; 1532 1533 PetscCall(DMGetLabelName(dm, l, &name)); 1534 PetscCall(DMGetLabel(dm, name, &label)); 1535 PetscCall(DMLabelGetNumValues(label, &numValues)); 1536 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1537 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1538 PetscCall(ISGetIndices(valueIS, &values)); 1539 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1540 for (v = 0; v < numValues; ++v) { 1541 PetscInt size; 1542 1543 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1544 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1545 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1546 } 1547 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1548 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1549 PetscCall(ISRestoreIndices(valueIS, &values)); 1550 PetscCall(ISDestroy(&valueIS)); 1551 } 1552 { 1553 char **labelNames; 1554 PetscInt Nl = numLabels; 1555 PetscBool flg; 1556 1557 PetscCall(PetscMalloc1(Nl, &labelNames)); 1558 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1559 for (l = 0; l < Nl; ++l) { 1560 DMLabel label; 1561 1562 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1563 if (flg) { 1564 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1565 PetscCall(DMLabelView(label, viewer)); 1566 } 1567 PetscCall(PetscFree(labelNames[l])); 1568 } 1569 PetscCall(PetscFree(labelNames)); 1570 } 1571 /* If no fields are specified, people do not want to see adjacency */ 1572 if (dm->Nf) { 1573 PetscInt f; 1574 1575 for (f = 0; f < dm->Nf; ++f) { 1576 const char *name; 1577 1578 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1579 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1580 PetscCall(PetscViewerASCIIPushTab(viewer)); 1581 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1582 if (dm->fields[f].adjacency[0]) { 1583 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1584 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1585 } else { 1586 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1587 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1588 } 1589 PetscCall(PetscViewerASCIIPopTab(viewer)); 1590 } 1591 } 1592 PetscCall(DMGetCoarseDM(dm, &cdm)); 1593 if (cdm) { 1594 PetscCall(PetscViewerASCIIPushTab(viewer)); 1595 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1596 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1597 PetscCall(PetscViewerASCIIPopTab(viewer)); 1598 } 1599 } 1600 PetscFunctionReturn(PETSC_SUCCESS); 1601 } 1602 1603 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1604 { 1605 DMPolytopeType ct; 1606 PetscMPIInt rank; 1607 PetscInt cdim; 1608 1609 PetscFunctionBegin; 1610 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1611 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1612 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1613 switch (ct) { 1614 case DM_POLYTOPE_SEGMENT: 1615 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1616 switch (cdim) { 1617 case 1: { 1618 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1619 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1620 1621 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1622 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1623 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1624 } break; 1625 case 2: { 1626 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1627 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1628 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1629 1630 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1631 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)); 1632 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)); 1633 } break; 1634 default: 1635 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1636 } 1637 break; 1638 case DM_POLYTOPE_TRIANGLE: 1639 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)); 1640 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1641 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1642 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1643 break; 1644 case DM_POLYTOPE_QUADRILATERAL: 1645 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)); 1646 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)); 1647 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1648 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1649 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1650 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1651 break; 1652 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1653 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)); 1654 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)); 1655 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1656 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1657 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1658 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1659 break; 1660 case DM_POLYTOPE_FV_GHOST: 1661 break; 1662 default: 1663 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1664 } 1665 PetscFunctionReturn(PETSC_SUCCESS); 1666 } 1667 1668 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1669 { 1670 DMPolytopeType ct; 1671 PetscReal centroid[2] = {0., 0.}; 1672 PetscMPIInt rank; 1673 PetscInt fillColor, v, e, d; 1674 1675 PetscFunctionBegin; 1676 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1677 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1678 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1679 switch (ct) { 1680 case DM_POLYTOPE_TRIANGLE: { 1681 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1682 1683 for (v = 0; v < 3; ++v) { 1684 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1685 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1686 } 1687 for (e = 0; e < 3; ++e) { 1688 refCoords[0] = refVertices[e * 2 + 0]; 1689 refCoords[1] = refVertices[e * 2 + 1]; 1690 for (d = 1; d <= edgeDiv; ++d) { 1691 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1692 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1693 } 1694 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1695 for (d = 0; d < edgeDiv; ++d) { 1696 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)); 1697 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1698 } 1699 } 1700 } break; 1701 default: 1702 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1703 } 1704 PetscFunctionReturn(PETSC_SUCCESS); 1705 } 1706 1707 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1708 { 1709 PetscDraw draw; 1710 DM cdm; 1711 PetscSection coordSection; 1712 Vec coordinates; 1713 PetscReal xyl[3], xyr[3]; 1714 PetscReal *refCoords, *edgeCoords; 1715 PetscBool isnull, drawAffine = PETSC_TRUE; 1716 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1717 1718 PetscFunctionBegin; 1719 PetscCall(DMGetCoordinateDim(dm, &dim)); 1720 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1721 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1722 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1723 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1724 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1725 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1726 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1727 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1728 1729 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1730 PetscCall(PetscDrawIsNull(draw, &isnull)); 1731 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1732 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1733 1734 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 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 const PetscScalar *coords_arr; 1741 PetscInt numCoords; 1742 PetscBool isDG; 1743 1744 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1745 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1746 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1747 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1748 } 1749 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1750 PetscCall(PetscDrawFlush(draw)); 1751 PetscCall(PetscDrawPause(draw)); 1752 PetscCall(PetscDrawSave(draw)); 1753 PetscFunctionReturn(PETSC_SUCCESS); 1754 } 1755 1756 #if defined(PETSC_HAVE_EXODUSII) 1757 #include <exodusII.h> 1758 #include <petscviewerexodusii.h> 1759 #endif 1760 1761 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1762 { 1763 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1764 char name[PETSC_MAX_PATH_LEN]; 1765 1766 PetscFunctionBegin; 1767 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1768 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1769 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1770 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1771 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1773 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1776 if (iascii) { 1777 PetscViewerFormat format; 1778 PetscCall(PetscViewerGetFormat(viewer, &format)); 1779 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1780 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1781 } else if (ishdf5) { 1782 #if defined(PETSC_HAVE_HDF5) 1783 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1784 #else 1785 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1786 #endif 1787 } else if (isvtk) { 1788 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1789 } else if (isdraw) { 1790 PetscCall(DMPlexView_Draw(dm, viewer)); 1791 } else if (isglvis) { 1792 PetscCall(DMPlexView_GLVis(dm, viewer)); 1793 #if defined(PETSC_HAVE_EXODUSII) 1794 } else if (isexodus) { 1795 /* 1796 exodusII requires that all sets be part of exactly one cell set. 1797 If the dm does not have a "Cell Sets" label defined, we create one 1798 with ID 1, containing all cells. 1799 Note that if the Cell Sets label is defined but does not cover all cells, 1800 we may still have a problem. This should probably be checked here or in the viewer; 1801 */ 1802 PetscInt numCS; 1803 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1804 if (!numCS) { 1805 PetscInt cStart, cEnd, c; 1806 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1807 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1808 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1809 } 1810 PetscCall(DMView_PlexExodusII(dm, viewer)); 1811 #endif 1812 #if defined(PETSC_HAVE_CGNS) 1813 } else if (iscgns) { 1814 PetscCall(DMView_PlexCGNS(dm, viewer)); 1815 #endif 1816 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1817 /* Optionally view the partition */ 1818 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1819 if (flg) { 1820 Vec ranks; 1821 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1822 PetscCall(VecView(ranks, viewer)); 1823 PetscCall(VecDestroy(&ranks)); 1824 } 1825 /* Optionally view a label */ 1826 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1827 if (flg) { 1828 DMLabel label; 1829 Vec val; 1830 1831 PetscCall(DMGetLabel(dm, name, &label)); 1832 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1833 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1834 PetscCall(VecView(val, viewer)); 1835 PetscCall(VecDestroy(&val)); 1836 } 1837 PetscFunctionReturn(PETSC_SUCCESS); 1838 } 1839 1840 /*@ 1841 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1842 1843 Collective 1844 1845 Input Parameters: 1846 + dm - The `DM` whose topology is to be saved 1847 - viewer - The `PetscViewer` to save it in 1848 1849 Level: advanced 1850 1851 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1852 @*/ 1853 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1854 { 1855 PetscBool ishdf5; 1856 1857 PetscFunctionBegin; 1858 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1859 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1860 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1861 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1862 if (ishdf5) { 1863 #if defined(PETSC_HAVE_HDF5) 1864 PetscViewerFormat format; 1865 PetscCall(PetscViewerGetFormat(viewer, &format)); 1866 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1867 IS globalPointNumbering; 1868 1869 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1870 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1871 PetscCall(ISDestroy(&globalPointNumbering)); 1872 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1873 #else 1874 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1875 #endif 1876 } 1877 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1878 PetscFunctionReturn(PETSC_SUCCESS); 1879 } 1880 1881 /*@ 1882 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 1883 1884 Collective 1885 1886 Input Parameters: 1887 + dm - The `DM` whose coordinates are to be saved 1888 - viewer - The `PetscViewer` for saving 1889 1890 Level: advanced 1891 1892 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 1893 @*/ 1894 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1895 { 1896 PetscBool ishdf5; 1897 1898 PetscFunctionBegin; 1899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1900 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1901 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1902 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1903 if (ishdf5) { 1904 #if defined(PETSC_HAVE_HDF5) 1905 PetscViewerFormat format; 1906 PetscCall(PetscViewerGetFormat(viewer, &format)); 1907 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1908 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1909 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1910 #else 1911 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1912 #endif 1913 } 1914 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1915 PetscFunctionReturn(PETSC_SUCCESS); 1916 } 1917 1918 /*@ 1919 DMPlexLabelsView - Saves `DMPLEX` labels into a file 1920 1921 Collective 1922 1923 Input Parameters: 1924 + dm - The `DM` whose labels are to be saved 1925 - viewer - The `PetscViewer` for saving 1926 1927 Level: advanced 1928 1929 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 1930 @*/ 1931 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1932 { 1933 PetscBool ishdf5; 1934 1935 PetscFunctionBegin; 1936 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1937 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1938 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1939 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1940 if (ishdf5) { 1941 #if defined(PETSC_HAVE_HDF5) 1942 IS globalPointNumbering; 1943 PetscViewerFormat format; 1944 1945 PetscCall(PetscViewerGetFormat(viewer, &format)); 1946 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1947 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1948 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1949 PetscCall(ISDestroy(&globalPointNumbering)); 1950 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1951 #else 1952 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1953 #endif 1954 } 1955 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1956 PetscFunctionReturn(PETSC_SUCCESS); 1957 } 1958 1959 /*@ 1960 DMPlexSectionView - Saves a section associated with a `DMPLEX` 1961 1962 Collective 1963 1964 Input Parameters: 1965 + dm - The `DM` that contains the topology on which the section to be saved is defined 1966 . viewer - The `PetscViewer` for saving 1967 - sectiondm - The `DM` that contains the section to be saved 1968 1969 Level: advanced 1970 1971 Notes: 1972 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. 1973 1974 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. 1975 1976 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 1977 @*/ 1978 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1979 { 1980 PetscBool ishdf5; 1981 1982 PetscFunctionBegin; 1983 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1984 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1985 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1986 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1987 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1988 if (ishdf5) { 1989 #if defined(PETSC_HAVE_HDF5) 1990 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1991 #else 1992 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1993 #endif 1994 } 1995 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1996 PetscFunctionReturn(PETSC_SUCCESS); 1997 } 1998 1999 /*@ 2000 DMPlexGlobalVectorView - Saves a global vector 2001 2002 Collective 2003 2004 Input Parameters: 2005 + dm - The `DM` that represents the topology 2006 . viewer - The `PetscViewer` to save data with 2007 . sectiondm - The `DM` that contains the global section on which vec is defined 2008 - vec - The global vector to be saved 2009 2010 Level: advanced 2011 2012 Notes: 2013 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. 2014 2015 Calling sequence: 2016 .vb 2017 DMCreate(PETSC_COMM_WORLD, &dm); 2018 DMSetType(dm, DMPLEX); 2019 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2020 DMClone(dm, §iondm); 2021 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2022 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2023 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2024 PetscSectionSetChart(section, pStart, pEnd); 2025 PetscSectionSetUp(section); 2026 DMSetLocalSection(sectiondm, section); 2027 PetscSectionDestroy(§ion); 2028 DMGetGlobalVector(sectiondm, &vec); 2029 PetscObjectSetName((PetscObject)vec, "vec_name"); 2030 DMPlexTopologyView(dm, viewer); 2031 DMPlexSectionView(dm, viewer, sectiondm); 2032 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2033 DMRestoreGlobalVector(sectiondm, &vec); 2034 DMDestroy(§iondm); 2035 DMDestroy(&dm); 2036 .ve 2037 2038 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2039 @*/ 2040 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2041 { 2042 PetscBool ishdf5; 2043 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2046 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2047 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2048 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2049 /* Check consistency */ 2050 { 2051 PetscSection section; 2052 PetscBool includesConstraints; 2053 PetscInt m, m1; 2054 2055 PetscCall(VecGetLocalSize(vec, &m1)); 2056 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2057 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2058 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2059 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2060 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2061 } 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2063 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2064 if (ishdf5) { 2065 #if defined(PETSC_HAVE_HDF5) 2066 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2067 #else 2068 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2069 #endif 2070 } 2071 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2072 PetscFunctionReturn(PETSC_SUCCESS); 2073 } 2074 2075 /*@ 2076 DMPlexLocalVectorView - Saves a local vector 2077 2078 Collective 2079 2080 Input Parameters: 2081 + dm - The `DM` that represents the topology 2082 . viewer - The `PetscViewer` to save data with 2083 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2084 - vec - The local vector to be saved 2085 2086 Level: advanced 2087 2088 Note: 2089 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. 2090 2091 Calling sequence: 2092 .vb 2093 DMCreate(PETSC_COMM_WORLD, &dm); 2094 DMSetType(dm, DMPLEX); 2095 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2096 DMClone(dm, §iondm); 2097 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2098 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2099 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2100 PetscSectionSetChart(section, pStart, pEnd); 2101 PetscSectionSetUp(section); 2102 DMSetLocalSection(sectiondm, section); 2103 DMGetLocalVector(sectiondm, &vec); 2104 PetscObjectSetName((PetscObject)vec, "vec_name"); 2105 DMPlexTopologyView(dm, viewer); 2106 DMPlexSectionView(dm, viewer, sectiondm); 2107 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2108 DMRestoreLocalVector(sectiondm, &vec); 2109 DMDestroy(§iondm); 2110 DMDestroy(&dm); 2111 .ve 2112 2113 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2114 @*/ 2115 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2116 { 2117 PetscBool ishdf5; 2118 2119 PetscFunctionBegin; 2120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2121 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2122 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2123 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2124 /* Check consistency */ 2125 { 2126 PetscSection section; 2127 PetscBool includesConstraints; 2128 PetscInt m, m1; 2129 2130 PetscCall(VecGetLocalSize(vec, &m1)); 2131 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2132 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2133 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2134 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2135 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2136 } 2137 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2138 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2139 if (ishdf5) { 2140 #if defined(PETSC_HAVE_HDF5) 2141 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2142 #else 2143 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2144 #endif 2145 } 2146 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2147 PetscFunctionReturn(PETSC_SUCCESS); 2148 } 2149 2150 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2151 { 2152 PetscBool ishdf5; 2153 2154 PetscFunctionBegin; 2155 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2156 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2157 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2158 if (ishdf5) { 2159 #if defined(PETSC_HAVE_HDF5) 2160 PetscViewerFormat format; 2161 PetscCall(PetscViewerGetFormat(viewer, &format)); 2162 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2163 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2164 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2165 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2166 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2167 PetscFunctionReturn(PETSC_SUCCESS); 2168 #else 2169 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2170 #endif 2171 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2172 } 2173 2174 /*@ 2175 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2176 2177 Collective 2178 2179 Input Parameters: 2180 + dm - The `DM` into which the topology is loaded 2181 - viewer - The `PetscViewer` for the saved topology 2182 2183 Output Parameter: 2184 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded 2185 2186 Level: advanced 2187 2188 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2189 `PetscViewer`, `PetscSF` 2190 @*/ 2191 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2192 { 2193 PetscBool ishdf5; 2194 2195 PetscFunctionBegin; 2196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2197 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2198 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2199 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2200 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2201 if (ishdf5) { 2202 #if defined(PETSC_HAVE_HDF5) 2203 PetscViewerFormat format; 2204 PetscCall(PetscViewerGetFormat(viewer, &format)); 2205 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2206 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2207 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2208 #else 2209 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2210 #endif 2211 } 2212 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2213 PetscFunctionReturn(PETSC_SUCCESS); 2214 } 2215 2216 /*@ 2217 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2218 2219 Collective 2220 2221 Input Parameters: 2222 + dm - The `DM` into which the coordinates are loaded 2223 . viewer - The `PetscViewer` for the saved coordinates 2224 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2225 2226 Level: advanced 2227 2228 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2229 `PetscSF`, `PetscViewer` 2230 @*/ 2231 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2232 { 2233 PetscBool ishdf5; 2234 2235 PetscFunctionBegin; 2236 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2237 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2238 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2239 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2240 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2241 if (ishdf5) { 2242 #if defined(PETSC_HAVE_HDF5) 2243 PetscViewerFormat format; 2244 PetscCall(PetscViewerGetFormat(viewer, &format)); 2245 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2246 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2247 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2248 #else 2249 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2250 #endif 2251 } 2252 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2253 PetscFunctionReturn(PETSC_SUCCESS); 2254 } 2255 2256 /*@ 2257 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2258 2259 Collective 2260 2261 Input Parameters: 2262 + dm - The `DM` into which the labels are loaded 2263 . viewer - The `PetscViewer` for the saved labels 2264 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2265 2266 Level: advanced 2267 2268 Note: 2269 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2270 2271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2272 `PetscSF`, `PetscViewer` 2273 @*/ 2274 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2275 { 2276 PetscBool ishdf5; 2277 2278 PetscFunctionBegin; 2279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2280 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2281 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2282 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2283 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2284 if (ishdf5) { 2285 #if defined(PETSC_HAVE_HDF5) 2286 PetscViewerFormat format; 2287 2288 PetscCall(PetscViewerGetFormat(viewer, &format)); 2289 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2290 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2291 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2292 #else 2293 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2294 #endif 2295 } 2296 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2297 PetscFunctionReturn(PETSC_SUCCESS); 2298 } 2299 2300 /*@ 2301 DMPlexSectionLoad - Loads section into a `DMPLEX` 2302 2303 Collective 2304 2305 Input Parameters: 2306 + dm - The `DM` that represents the topology 2307 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2308 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2309 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2310 2311 Output Parameters: 2312 + globalDofSF - The `PetscSF` 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) 2313 - localDofSF - The `PetscSF` 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) 2314 2315 Level: advanced 2316 2317 Notes: 2318 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. 2319 2320 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. 2321 2322 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. 2323 2324 Example using 2 processes: 2325 .vb 2326 NX (number of points on dm): 4 2327 sectionA : the on-disk section 2328 vecA : a vector associated with sectionA 2329 sectionB : sectiondm's local section constructed in this function 2330 vecB (local) : a vector associated with sectiondm's local section 2331 vecB (global) : a vector associated with sectiondm's global section 2332 2333 rank 0 rank 1 2334 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2335 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2336 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2337 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2338 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2339 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2340 sectionB->atlasDof : 1 0 1 | 1 3 2341 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2342 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2343 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2344 .ve 2345 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2346 2347 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2348 @*/ 2349 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2350 { 2351 PetscBool ishdf5; 2352 2353 PetscFunctionBegin; 2354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2355 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2356 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2357 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2358 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2359 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2360 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2361 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2362 if (ishdf5) { 2363 #if defined(PETSC_HAVE_HDF5) 2364 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2365 #else 2366 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2367 #endif 2368 } 2369 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2370 PetscFunctionReturn(PETSC_SUCCESS); 2371 } 2372 2373 /*@ 2374 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2375 2376 Collective 2377 2378 Input Parameters: 2379 + dm - The `DM` that represents the topology 2380 . viewer - The `PetscViewer` that represents the on-disk vector data 2381 . sectiondm - The `DM` that contains the global section on which vec is defined 2382 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2383 - vec - The global vector to set values of 2384 2385 Level: advanced 2386 2387 Notes: 2388 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. 2389 2390 Calling sequence: 2391 .vb 2392 DMCreate(PETSC_COMM_WORLD, &dm); 2393 DMSetType(dm, DMPLEX); 2394 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2395 DMPlexTopologyLoad(dm, viewer, &sfX); 2396 DMClone(dm, §iondm); 2397 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2398 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2399 DMGetGlobalVector(sectiondm, &vec); 2400 PetscObjectSetName((PetscObject)vec, "vec_name"); 2401 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2402 DMRestoreGlobalVector(sectiondm, &vec); 2403 PetscSFDestroy(&gsf); 2404 PetscSFDestroy(&sfX); 2405 DMDestroy(§iondm); 2406 DMDestroy(&dm); 2407 .ve 2408 2409 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2410 `PetscSF`, `PetscViewer` 2411 @*/ 2412 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2413 { 2414 PetscBool ishdf5; 2415 2416 PetscFunctionBegin; 2417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2418 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2419 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2420 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2421 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2422 /* Check consistency */ 2423 { 2424 PetscSection section; 2425 PetscBool includesConstraints; 2426 PetscInt m, m1; 2427 2428 PetscCall(VecGetLocalSize(vec, &m1)); 2429 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2430 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2431 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2432 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2433 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2434 } 2435 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2436 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2437 if (ishdf5) { 2438 #if defined(PETSC_HAVE_HDF5) 2439 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2440 #else 2441 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2442 #endif 2443 } 2444 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2445 PetscFunctionReturn(PETSC_SUCCESS); 2446 } 2447 2448 /*@ 2449 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2450 2451 Collective 2452 2453 Input Parameters: 2454 + dm - The `DM` that represents the topology 2455 . viewer - The `PetscViewer` that represents the on-disk vector data 2456 . sectiondm - The `DM` that contains the local section on which vec is defined 2457 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2458 - vec - The local vector to set values of 2459 2460 Level: advanced 2461 2462 Notes: 2463 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. 2464 2465 Calling sequence: 2466 .vb 2467 DMCreate(PETSC_COMM_WORLD, &dm); 2468 DMSetType(dm, DMPLEX); 2469 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2470 DMPlexTopologyLoad(dm, viewer, &sfX); 2471 DMClone(dm, §iondm); 2472 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2473 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2474 DMGetLocalVector(sectiondm, &vec); 2475 PetscObjectSetName((PetscObject)vec, "vec_name"); 2476 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2477 DMRestoreLocalVector(sectiondm, &vec); 2478 PetscSFDestroy(&lsf); 2479 PetscSFDestroy(&sfX); 2480 DMDestroy(§iondm); 2481 DMDestroy(&dm); 2482 .ve 2483 2484 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2485 `PetscSF`, `PetscViewer` 2486 @*/ 2487 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2488 { 2489 PetscBool ishdf5; 2490 2491 PetscFunctionBegin; 2492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2493 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2494 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2495 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2496 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2497 /* Check consistency */ 2498 { 2499 PetscSection section; 2500 PetscBool includesConstraints; 2501 PetscInt m, m1; 2502 2503 PetscCall(VecGetLocalSize(vec, &m1)); 2504 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2505 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2506 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2507 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2508 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2509 } 2510 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2511 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2512 if (ishdf5) { 2513 #if defined(PETSC_HAVE_HDF5) 2514 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2515 #else 2516 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2517 #endif 2518 } 2519 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2520 PetscFunctionReturn(PETSC_SUCCESS); 2521 } 2522 2523 PetscErrorCode DMDestroy_Plex(DM dm) 2524 { 2525 DM_Plex *mesh = (DM_Plex *)dm->data; 2526 2527 PetscFunctionBegin; 2528 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2529 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2530 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2531 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2532 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2533 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2534 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2535 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2536 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2537 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2538 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2539 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2540 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2541 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2542 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2543 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2544 PetscCall(PetscFree(mesh->cones)); 2545 PetscCall(PetscFree(mesh->coneOrientations)); 2546 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2547 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2548 PetscCall(PetscFree(mesh->supports)); 2549 PetscCall(PetscFree(mesh->cellTypes)); 2550 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2551 PetscCall(PetscFree(mesh->tetgenOpts)); 2552 PetscCall(PetscFree(mesh->triangleOpts)); 2553 PetscCall(PetscFree(mesh->transformType)); 2554 PetscCall(PetscFree(mesh->distributionName)); 2555 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2556 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2557 PetscCall(ISDestroy(&mesh->subpointIS)); 2558 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2559 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2560 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2561 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2562 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2563 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2564 PetscCall(ISDestroy(&mesh->anchorIS)); 2565 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2566 PetscCall(PetscFree(mesh->parents)); 2567 PetscCall(PetscFree(mesh->childIDs)); 2568 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2569 PetscCall(PetscFree(mesh->children)); 2570 PetscCall(DMDestroy(&mesh->referenceTree)); 2571 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2572 PetscCall(PetscFree(mesh->neighbors)); 2573 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2574 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2575 PetscCall(PetscFree(mesh)); 2576 PetscFunctionReturn(PETSC_SUCCESS); 2577 } 2578 2579 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2580 { 2581 PetscSection sectionGlobal; 2582 PetscInt bs = -1, mbs; 2583 PetscInt localSize, localStart = 0; 2584 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2585 MatType mtype; 2586 ISLocalToGlobalMapping ltog; 2587 2588 PetscFunctionBegin; 2589 PetscCall(MatInitializePackage()); 2590 mtype = dm->mattype; 2591 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2592 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2593 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2594 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2595 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2596 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2597 PetscCall(MatSetType(*J, mtype)); 2598 PetscCall(MatSetFromOptions(*J)); 2599 PetscCall(MatGetBlockSize(*J, &mbs)); 2600 if (mbs > 1) bs = mbs; 2601 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2602 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2603 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2604 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2605 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2606 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2607 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2608 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2609 if (!isShell) { 2610 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2611 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2612 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2613 2614 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2615 2616 PetscCall(PetscCalloc1(localSize, &pblocks)); 2617 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2618 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2619 for (p = pStart; p < pEnd; ++p) { 2620 switch (dm->blocking_type) { 2621 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2622 PetscInt bdof, offset; 2623 2624 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2625 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2626 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2627 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2628 dof = dof < 0 ? -(dof + 1) : dof; 2629 bdof = cdof && (dof - cdof) ? 1 : dof; 2630 if (dof) { 2631 if (bs < 0) { 2632 bs = bdof; 2633 } else if (bs != bdof) { 2634 bs = 1; 2635 } 2636 } 2637 } break; 2638 case DM_BLOCKING_FIELD_NODE: { 2639 for (PetscInt field = 0; field < num_fields; field++) { 2640 PetscInt num_comp, bdof, offset; 2641 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2642 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2643 if (dof < 0) continue; 2644 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2645 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2646 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2647 PetscInt num_nodes = dof / num_comp; 2648 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2649 // Handle possibly constant block size (unlikely) 2650 bdof = cdof && (dof - cdof) ? 1 : dof; 2651 if (dof) { 2652 if (bs < 0) { 2653 bs = bdof; 2654 } else if (bs != bdof) { 2655 bs = 1; 2656 } 2657 } 2658 } 2659 } break; 2660 } 2661 } 2662 /* Must have same blocksize on all procs (some might have no points) */ 2663 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2664 bsLocal[1] = bs; 2665 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2666 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2667 else bs = bsMinMax[0]; 2668 bs = PetscMax(1, bs); 2669 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2670 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2671 PetscCall(MatSetBlockSize(*J, bs)); 2672 PetscCall(MatSetUp(*J)); 2673 } else { 2674 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2675 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2676 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2677 } 2678 { // Consolidate blocks 2679 PetscInt nblocks = 0; 2680 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2681 if (pblocks[i] == 0) continue; 2682 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2683 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]); 2684 } 2685 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2686 } 2687 PetscCall(PetscFree(pblocks)); 2688 } 2689 PetscCall(MatSetDM(*J, dm)); 2690 PetscFunctionReturn(PETSC_SUCCESS); 2691 } 2692 2693 /*@ 2694 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2695 2696 Not Collective 2697 2698 Input Parameter: 2699 . dm - The `DMPLEX` 2700 2701 Output Parameter: 2702 . subsection - The subdomain section 2703 2704 Level: developer 2705 2706 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2707 @*/ 2708 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2709 { 2710 DM_Plex *mesh = (DM_Plex *)dm->data; 2711 2712 PetscFunctionBegin; 2713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2714 if (!mesh->subdomainSection) { 2715 PetscSection section; 2716 PetscSF sf; 2717 2718 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2719 PetscCall(DMGetLocalSection(dm, §ion)); 2720 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2721 PetscCall(PetscSFDestroy(&sf)); 2722 } 2723 *subsection = mesh->subdomainSection; 2724 PetscFunctionReturn(PETSC_SUCCESS); 2725 } 2726 2727 /*@ 2728 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2729 2730 Not Collective 2731 2732 Input Parameter: 2733 . dm - The `DMPLEX` 2734 2735 Output Parameters: 2736 + pStart - The first mesh point 2737 - pEnd - The upper bound for mesh points 2738 2739 Level: beginner 2740 2741 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2742 @*/ 2743 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2744 { 2745 DM_Plex *mesh = (DM_Plex *)dm->data; 2746 2747 PetscFunctionBegin; 2748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2749 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2750 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2751 PetscFunctionReturn(PETSC_SUCCESS); 2752 } 2753 2754 /*@ 2755 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2756 2757 Not Collective 2758 2759 Input Parameters: 2760 + dm - The `DMPLEX` 2761 . pStart - The first mesh point 2762 - pEnd - The upper bound for mesh points 2763 2764 Level: beginner 2765 2766 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2767 @*/ 2768 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2769 { 2770 DM_Plex *mesh = (DM_Plex *)dm->data; 2771 2772 PetscFunctionBegin; 2773 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2774 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2775 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2776 PetscCall(PetscFree(mesh->cellTypes)); 2777 PetscFunctionReturn(PETSC_SUCCESS); 2778 } 2779 2780 /*@ 2781 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2782 2783 Not Collective 2784 2785 Input Parameters: 2786 + dm - The `DMPLEX` 2787 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2788 2789 Output Parameter: 2790 . size - The cone size for point `p` 2791 2792 Level: beginner 2793 2794 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2795 @*/ 2796 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2797 { 2798 DM_Plex *mesh = (DM_Plex *)dm->data; 2799 2800 PetscFunctionBegin; 2801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2802 PetscAssertPointer(size, 3); 2803 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2804 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2805 PetscFunctionReturn(PETSC_SUCCESS); 2806 } 2807 2808 /*@ 2809 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2810 2811 Not Collective 2812 2813 Input Parameters: 2814 + dm - The `DMPLEX` 2815 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2816 - size - The cone size for point `p` 2817 2818 Level: beginner 2819 2820 Note: 2821 This should be called after `DMPlexSetChart()`. 2822 2823 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2824 @*/ 2825 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2826 { 2827 DM_Plex *mesh = (DM_Plex *)dm->data; 2828 2829 PetscFunctionBegin; 2830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2831 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2832 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2833 PetscFunctionReturn(PETSC_SUCCESS); 2834 } 2835 2836 /*@C 2837 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2838 2839 Not Collective 2840 2841 Input Parameters: 2842 + dm - The `DMPLEX` 2843 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2844 2845 Output Parameter: 2846 . cone - An array of points which are on the in-edges for point `p` 2847 2848 Level: beginner 2849 2850 Fortran Notes: 2851 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2852 `DMPlexRestoreCone()` is not needed/available in C. 2853 2854 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 2855 @*/ 2856 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2857 { 2858 DM_Plex *mesh = (DM_Plex *)dm->data; 2859 PetscInt off; 2860 2861 PetscFunctionBegin; 2862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2863 PetscAssertPointer(cone, 3); 2864 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2865 *cone = &mesh->cones[off]; 2866 PetscFunctionReturn(PETSC_SUCCESS); 2867 } 2868 2869 /*@C 2870 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2871 2872 Not Collective 2873 2874 Input Parameters: 2875 + dm - The `DMPLEX` 2876 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2877 2878 Output Parameters: 2879 + pConesSection - `PetscSection` describing the layout of `pCones` 2880 - pCones - An array of points which are on the in-edges for the point set `p` 2881 2882 Level: intermediate 2883 2884 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 2885 @*/ 2886 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2887 { 2888 PetscSection cs, newcs; 2889 PetscInt *cones; 2890 PetscInt *newarr = NULL; 2891 PetscInt n; 2892 2893 PetscFunctionBegin; 2894 PetscCall(DMPlexGetCones(dm, &cones)); 2895 PetscCall(DMPlexGetConeSection(dm, &cs)); 2896 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2897 if (pConesSection) *pConesSection = newcs; 2898 if (pCones) { 2899 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2900 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2901 } 2902 PetscFunctionReturn(PETSC_SUCCESS); 2903 } 2904 2905 /*@ 2906 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2907 2908 Not Collective 2909 2910 Input Parameters: 2911 + dm - The `DMPLEX` 2912 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2913 2914 Output Parameter: 2915 . expandedPoints - An array of vertices recursively expanded from input points 2916 2917 Level: advanced 2918 2919 Notes: 2920 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 2921 2922 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 2923 2924 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 2925 `DMPlexGetDepth()`, `IS` 2926 @*/ 2927 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2928 { 2929 IS *expandedPointsAll; 2930 PetscInt depth; 2931 2932 PetscFunctionBegin; 2933 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2934 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2935 PetscAssertPointer(expandedPoints, 3); 2936 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2937 *expandedPoints = expandedPointsAll[0]; 2938 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2939 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2940 PetscFunctionReturn(PETSC_SUCCESS); 2941 } 2942 2943 /*@ 2944 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). 2945 2946 Not Collective 2947 2948 Input Parameters: 2949 + dm - The `DMPLEX` 2950 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2951 2952 Output Parameters: 2953 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 2954 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2955 - sections - (optional) An array of sections which describe mappings from points to their cone points 2956 2957 Level: advanced 2958 2959 Notes: 2960 Like `DMPlexGetConeTuple()` but recursive. 2961 2962 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. 2963 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2964 2965 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\: 2966 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 2967 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 2968 2969 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 2970 `DMPlexGetDepth()`, `PetscSection`, `IS` 2971 @*/ 2972 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2973 { 2974 const PetscInt *arr0 = NULL, *cone = NULL; 2975 PetscInt *arr = NULL, *newarr = NULL; 2976 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2977 IS *expandedPoints_; 2978 PetscSection *sections_; 2979 2980 PetscFunctionBegin; 2981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2982 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2983 if (depth) PetscAssertPointer(depth, 3); 2984 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 2985 if (sections) PetscAssertPointer(sections, 5); 2986 PetscCall(ISGetLocalSize(points, &n)); 2987 PetscCall(ISGetIndices(points, &arr0)); 2988 PetscCall(DMPlexGetDepth(dm, &depth_)); 2989 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2990 PetscCall(PetscCalloc1(depth_, §ions_)); 2991 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2992 for (d = depth_ - 1; d >= 0; d--) { 2993 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2994 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2995 for (i = 0; i < n; i++) { 2996 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2997 if (arr[i] >= start && arr[i] < end) { 2998 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2999 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3000 } else { 3001 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3002 } 3003 } 3004 PetscCall(PetscSectionSetUp(sections_[d])); 3005 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3006 PetscCall(PetscMalloc1(newn, &newarr)); 3007 for (i = 0; i < n; i++) { 3008 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3009 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3010 if (cn > 1) { 3011 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3012 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3013 } else { 3014 newarr[co] = arr[i]; 3015 } 3016 } 3017 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3018 arr = newarr; 3019 n = newn; 3020 } 3021 PetscCall(ISRestoreIndices(points, &arr0)); 3022 *depth = depth_; 3023 if (expandedPoints) *expandedPoints = expandedPoints_; 3024 else { 3025 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3026 PetscCall(PetscFree(expandedPoints_)); 3027 } 3028 if (sections) *sections = sections_; 3029 else { 3030 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3031 PetscCall(PetscFree(sections_)); 3032 } 3033 PetscFunctionReturn(PETSC_SUCCESS); 3034 } 3035 3036 /*@ 3037 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3038 3039 Not Collective 3040 3041 Input Parameters: 3042 + dm - The `DMPLEX` 3043 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3044 3045 Output Parameters: 3046 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3047 . expandedPoints - (optional) An array of recursively expanded cones 3048 - sections - (optional) An array of sections which describe mappings from points to their cone points 3049 3050 Level: advanced 3051 3052 Note: 3053 See `DMPlexGetConeRecursive()` 3054 3055 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3056 `DMPlexGetDepth()`, `IS`, `PetscSection` 3057 @*/ 3058 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3059 { 3060 PetscInt d, depth_; 3061 3062 PetscFunctionBegin; 3063 PetscCall(DMPlexGetDepth(dm, &depth_)); 3064 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3065 if (depth) *depth = 0; 3066 if (expandedPoints) { 3067 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3068 PetscCall(PetscFree(*expandedPoints)); 3069 } 3070 if (sections) { 3071 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3072 PetscCall(PetscFree(*sections)); 3073 } 3074 PetscFunctionReturn(PETSC_SUCCESS); 3075 } 3076 3077 /*@ 3078 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 3079 3080 Not Collective 3081 3082 Input Parameters: 3083 + dm - The `DMPLEX` 3084 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3085 - cone - An array of points which are on the in-edges for point `p` 3086 3087 Level: beginner 3088 3089 Note: 3090 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3091 3092 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3093 @*/ 3094 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3095 { 3096 DM_Plex *mesh = (DM_Plex *)dm->data; 3097 PetscInt dof, off, c; 3098 3099 PetscFunctionBegin; 3100 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3101 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3102 if (dof) PetscAssertPointer(cone, 3); 3103 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3104 if (PetscDefined(USE_DEBUG)) { 3105 PetscInt pStart, pEnd; 3106 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3107 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); 3108 for (c = 0; c < dof; ++c) { 3109 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); 3110 mesh->cones[off + c] = cone[c]; 3111 } 3112 } else { 3113 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3114 } 3115 PetscFunctionReturn(PETSC_SUCCESS); 3116 } 3117 3118 /*@C 3119 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3120 3121 Not Collective 3122 3123 Input Parameters: 3124 + dm - The `DMPLEX` 3125 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3126 3127 Output Parameter: 3128 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3129 integer giving the prescription for cone traversal. 3130 3131 Level: beginner 3132 3133 Note: 3134 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3135 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3136 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3137 with the identity. 3138 3139 Fortran Notes: 3140 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3141 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3142 3143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3144 @*/ 3145 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3146 { 3147 DM_Plex *mesh = (DM_Plex *)dm->data; 3148 PetscInt off; 3149 3150 PetscFunctionBegin; 3151 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3152 if (PetscDefined(USE_DEBUG)) { 3153 PetscInt dof; 3154 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3155 if (dof) PetscAssertPointer(coneOrientation, 3); 3156 } 3157 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3158 3159 *coneOrientation = &mesh->coneOrientations[off]; 3160 PetscFunctionReturn(PETSC_SUCCESS); 3161 } 3162 3163 /*@ 3164 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3165 3166 Not Collective 3167 3168 Input Parameters: 3169 + dm - The `DMPLEX` 3170 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3171 - coneOrientation - An array of orientations 3172 3173 Level: beginner 3174 3175 Notes: 3176 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3177 3178 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3179 3180 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3181 @*/ 3182 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3183 { 3184 DM_Plex *mesh = (DM_Plex *)dm->data; 3185 PetscInt pStart, pEnd; 3186 PetscInt dof, off, c; 3187 3188 PetscFunctionBegin; 3189 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3190 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3191 if (dof) PetscAssertPointer(coneOrientation, 3); 3192 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3193 if (PetscDefined(USE_DEBUG)) { 3194 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3195 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); 3196 for (c = 0; c < dof; ++c) { 3197 PetscInt cdof, o = coneOrientation[c]; 3198 3199 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3200 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); 3201 mesh->coneOrientations[off + c] = o; 3202 } 3203 } else { 3204 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3205 } 3206 PetscFunctionReturn(PETSC_SUCCESS); 3207 } 3208 3209 /*@ 3210 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3211 3212 Not Collective 3213 3214 Input Parameters: 3215 + dm - The `DMPLEX` 3216 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3217 . conePos - The local index in the cone where the point should be put 3218 - conePoint - The mesh point to insert 3219 3220 Level: beginner 3221 3222 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3223 @*/ 3224 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3225 { 3226 DM_Plex *mesh = (DM_Plex *)dm->data; 3227 PetscInt pStart, pEnd; 3228 PetscInt dof, off; 3229 3230 PetscFunctionBegin; 3231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3232 if (PetscDefined(USE_DEBUG)) { 3233 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3234 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); 3235 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); 3236 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3237 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); 3238 } 3239 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3240 mesh->cones[off + conePos] = conePoint; 3241 PetscFunctionReturn(PETSC_SUCCESS); 3242 } 3243 3244 /*@ 3245 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3246 3247 Not Collective 3248 3249 Input Parameters: 3250 + dm - The `DMPLEX` 3251 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3252 . conePos - The local index in the cone where the point should be put 3253 - coneOrientation - The point orientation to insert 3254 3255 Level: beginner 3256 3257 Note: 3258 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3259 3260 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3261 @*/ 3262 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3263 { 3264 DM_Plex *mesh = (DM_Plex *)dm->data; 3265 PetscInt pStart, pEnd; 3266 PetscInt dof, off; 3267 3268 PetscFunctionBegin; 3269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3270 if (PetscDefined(USE_DEBUG)) { 3271 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3272 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); 3273 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3274 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); 3275 } 3276 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3277 mesh->coneOrientations[off + conePos] = coneOrientation; 3278 PetscFunctionReturn(PETSC_SUCCESS); 3279 } 3280 3281 /*@C 3282 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3283 3284 Not collective 3285 3286 Input Parameters: 3287 + dm - The DMPlex 3288 - p - The point, which must lie in the chart set with DMPlexSetChart() 3289 3290 Output Parameters: 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 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3305 `DMPlexRestoreCone()` is not needed/available in C. 3306 3307 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3308 @*/ 3309 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3310 { 3311 DM_Plex *mesh = (DM_Plex *)dm->data; 3312 3313 PetscFunctionBegin; 3314 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3315 if (mesh->tr) { 3316 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3317 } else { 3318 PetscInt off; 3319 if (PetscDefined(USE_DEBUG)) { 3320 PetscInt dof; 3321 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3322 if (dof) { 3323 if (cone) PetscAssertPointer(cone, 3); 3324 if (ornt) PetscAssertPointer(ornt, 4); 3325 } 3326 } 3327 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3328 if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB 3329 if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL; 3330 } 3331 PetscFunctionReturn(PETSC_SUCCESS); 3332 } 3333 3334 /*@C 3335 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3336 3337 Not Collective 3338 3339 Input Parameters: 3340 + dm - The DMPlex 3341 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3342 . cone - An array of points which are on the in-edges for point p 3343 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3344 integer giving the prescription for cone traversal. 3345 3346 Level: beginner 3347 3348 Notes: 3349 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3350 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3351 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3352 with the identity. 3353 3354 Fortran Notes: 3355 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3356 `DMPlexRestoreCone()` is not needed/available in C. 3357 3358 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3359 @*/ 3360 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3361 { 3362 DM_Plex *mesh = (DM_Plex *)dm->data; 3363 3364 PetscFunctionBegin; 3365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3366 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3367 PetscFunctionReturn(PETSC_SUCCESS); 3368 } 3369 3370 /*@ 3371 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3372 3373 Not Collective 3374 3375 Input Parameters: 3376 + dm - The `DMPLEX` 3377 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3378 3379 Output Parameter: 3380 . size - The support size for point `p` 3381 3382 Level: beginner 3383 3384 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3385 @*/ 3386 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3387 { 3388 DM_Plex *mesh = (DM_Plex *)dm->data; 3389 3390 PetscFunctionBegin; 3391 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3392 PetscAssertPointer(size, 3); 3393 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3394 PetscFunctionReturn(PETSC_SUCCESS); 3395 } 3396 3397 /*@ 3398 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3399 3400 Not Collective 3401 3402 Input Parameters: 3403 + dm - The `DMPLEX` 3404 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3405 - size - The support size for point `p` 3406 3407 Level: beginner 3408 3409 Note: 3410 This should be called after `DMPlexSetChart()`. 3411 3412 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3413 @*/ 3414 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3415 { 3416 DM_Plex *mesh = (DM_Plex *)dm->data; 3417 3418 PetscFunctionBegin; 3419 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3420 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3421 PetscFunctionReturn(PETSC_SUCCESS); 3422 } 3423 3424 /*@C 3425 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3426 3427 Not Collective 3428 3429 Input Parameters: 3430 + dm - The `DMPLEX` 3431 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3432 3433 Output Parameter: 3434 . support - An array of points which are on the out-edges for point `p` 3435 3436 Level: beginner 3437 3438 Fortran Notes: 3439 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3440 `DMPlexRestoreSupport()` is not needed/available in C. 3441 3442 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3443 @*/ 3444 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3445 { 3446 DM_Plex *mesh = (DM_Plex *)dm->data; 3447 PetscInt off; 3448 3449 PetscFunctionBegin; 3450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3451 PetscAssertPointer(support, 3); 3452 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3453 *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB 3454 PetscFunctionReturn(PETSC_SUCCESS); 3455 } 3456 3457 /*@ 3458 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3459 3460 Not Collective 3461 3462 Input Parameters: 3463 + dm - The `DMPLEX` 3464 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3465 - support - An array of points which are on the out-edges for point `p` 3466 3467 Level: beginner 3468 3469 Note: 3470 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3471 3472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3473 @*/ 3474 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3475 { 3476 DM_Plex *mesh = (DM_Plex *)dm->data; 3477 PetscInt pStart, pEnd; 3478 PetscInt dof, off, c; 3479 3480 PetscFunctionBegin; 3481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3482 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3483 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3484 if (dof) PetscAssertPointer(support, 3); 3485 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3486 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); 3487 for (c = 0; c < dof; ++c) { 3488 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); 3489 mesh->supports[off + c] = support[c]; 3490 } 3491 PetscFunctionReturn(PETSC_SUCCESS); 3492 } 3493 3494 /*@ 3495 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3496 3497 Not Collective 3498 3499 Input Parameters: 3500 + dm - The `DMPLEX` 3501 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3502 . supportPos - The local index in the cone where the point should be put 3503 - supportPoint - The mesh point to insert 3504 3505 Level: beginner 3506 3507 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3508 @*/ 3509 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3510 { 3511 DM_Plex *mesh = (DM_Plex *)dm->data; 3512 PetscInt pStart, pEnd; 3513 PetscInt dof, off; 3514 3515 PetscFunctionBegin; 3516 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3517 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3518 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3519 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3520 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); 3521 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); 3522 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); 3523 mesh->supports[off + supportPos] = supportPoint; 3524 PetscFunctionReturn(PETSC_SUCCESS); 3525 } 3526 3527 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3528 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3529 { 3530 switch (ct) { 3531 case DM_POLYTOPE_SEGMENT: 3532 if (o == -1) return -2; 3533 break; 3534 case DM_POLYTOPE_TRIANGLE: 3535 if (o == -3) return -1; 3536 if (o == -2) return -3; 3537 if (o == -1) return -2; 3538 break; 3539 case DM_POLYTOPE_QUADRILATERAL: 3540 if (o == -4) return -2; 3541 if (o == -3) return -1; 3542 if (o == -2) return -4; 3543 if (o == -1) return -3; 3544 break; 3545 default: 3546 return o; 3547 } 3548 return o; 3549 } 3550 3551 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3552 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3553 { 3554 switch (ct) { 3555 case DM_POLYTOPE_SEGMENT: 3556 if ((o == -2) || (o == 1)) return -1; 3557 if (o == -1) return 0; 3558 break; 3559 case DM_POLYTOPE_TRIANGLE: 3560 if (o == -3) return -2; 3561 if (o == -2) return -1; 3562 if (o == -1) return -3; 3563 break; 3564 case DM_POLYTOPE_QUADRILATERAL: 3565 if (o == -4) return -2; 3566 if (o == -3) return -1; 3567 if (o == -2) return -4; 3568 if (o == -1) return -3; 3569 break; 3570 default: 3571 return o; 3572 } 3573 return o; 3574 } 3575 3576 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3577 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3578 { 3579 PetscInt pStart, pEnd, p; 3580 3581 PetscFunctionBegin; 3582 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3583 for (p = pStart; p < pEnd; ++p) { 3584 const PetscInt *cone, *ornt; 3585 PetscInt coneSize, c; 3586 3587 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3588 PetscCall(DMPlexGetCone(dm, p, &cone)); 3589 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3590 for (c = 0; c < coneSize; ++c) { 3591 DMPolytopeType ct; 3592 const PetscInt o = ornt[c]; 3593 3594 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3595 switch (ct) { 3596 case DM_POLYTOPE_SEGMENT: 3597 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3598 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3599 break; 3600 case DM_POLYTOPE_TRIANGLE: 3601 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3602 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3603 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3604 break; 3605 case DM_POLYTOPE_QUADRILATERAL: 3606 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3607 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3608 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3609 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3610 break; 3611 default: 3612 break; 3613 } 3614 } 3615 } 3616 PetscFunctionReturn(PETSC_SUCCESS); 3617 } 3618 3619 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3620 { 3621 DM_Plex *mesh = (DM_Plex *)dm->data; 3622 3623 PetscFunctionBeginHot; 3624 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3625 if (useCone) { 3626 PetscCall(DMPlexGetConeSize(dm, p, size)); 3627 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3628 } else { 3629 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3630 PetscCall(DMPlexGetSupport(dm, p, arr)); 3631 } 3632 } else { 3633 if (useCone) { 3634 const PetscSection s = mesh->coneSection; 3635 const PetscInt ps = p - s->pStart; 3636 const PetscInt off = s->atlasOff[ps]; 3637 3638 *size = s->atlasDof[ps]; 3639 *arr = mesh->cones + off; 3640 *ornt = mesh->coneOrientations + off; 3641 } else { 3642 const PetscSection s = mesh->supportSection; 3643 const PetscInt ps = p - s->pStart; 3644 const PetscInt off = s->atlasOff[ps]; 3645 3646 *size = s->atlasDof[ps]; 3647 *arr = mesh->supports + off; 3648 } 3649 } 3650 PetscFunctionReturn(PETSC_SUCCESS); 3651 } 3652 3653 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3654 { 3655 DM_Plex *mesh = (DM_Plex *)dm->data; 3656 3657 PetscFunctionBeginHot; 3658 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3659 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3660 } 3661 PetscFunctionReturn(PETSC_SUCCESS); 3662 } 3663 3664 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3665 { 3666 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3667 PetscInt *closure; 3668 const PetscInt *tmp = NULL, *tmpO = NULL; 3669 PetscInt off = 0, tmpSize, t; 3670 3671 PetscFunctionBeginHot; 3672 if (ornt) { 3673 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3674 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3675 } 3676 if (*points) { 3677 closure = *points; 3678 } else { 3679 PetscInt maxConeSize, maxSupportSize; 3680 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3681 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3682 } 3683 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3684 if (ct == DM_POLYTOPE_UNKNOWN) { 3685 closure[off++] = p; 3686 closure[off++] = 0; 3687 for (t = 0; t < tmpSize; ++t) { 3688 closure[off++] = tmp[t]; 3689 closure[off++] = tmpO ? tmpO[t] : 0; 3690 } 3691 } else { 3692 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3693 3694 /* We assume that cells with a valid type have faces with a valid type */ 3695 closure[off++] = p; 3696 closure[off++] = ornt; 3697 for (t = 0; t < tmpSize; ++t) { 3698 DMPolytopeType ft; 3699 3700 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3701 closure[off++] = tmp[arr[t]]; 3702 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3703 } 3704 } 3705 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3706 if (numPoints) *numPoints = tmpSize + 1; 3707 if (points) *points = closure; 3708 PetscFunctionReturn(PETSC_SUCCESS); 3709 } 3710 3711 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3712 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3713 { 3714 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3715 const PetscInt *cone, *ornt; 3716 PetscInt *pts, *closure = NULL; 3717 DMPolytopeType ft; 3718 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3719 PetscInt dim, coneSize, c, d, clSize, cl; 3720 3721 PetscFunctionBeginHot; 3722 PetscCall(DMGetDimension(dm, &dim)); 3723 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3724 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3725 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3726 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3727 maxSize = PetscMax(coneSeries, supportSeries); 3728 if (*points) { 3729 pts = *points; 3730 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3731 c = 0; 3732 pts[c++] = point; 3733 pts[c++] = o; 3734 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3735 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3736 for (cl = 0; cl < clSize * 2; cl += 2) { 3737 pts[c++] = closure[cl]; 3738 pts[c++] = closure[cl + 1]; 3739 } 3740 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3741 for (cl = 0; cl < clSize * 2; cl += 2) { 3742 pts[c++] = closure[cl]; 3743 pts[c++] = closure[cl + 1]; 3744 } 3745 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3746 for (d = 2; d < coneSize; ++d) { 3747 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3748 pts[c++] = cone[arr[d * 2 + 0]]; 3749 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3750 } 3751 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3752 if (dim >= 3) { 3753 for (d = 2; d < coneSize; ++d) { 3754 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3755 const PetscInt *fcone, *fornt; 3756 PetscInt fconeSize, fc, i; 3757 3758 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3759 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3760 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3761 for (fc = 0; fc < fconeSize; ++fc) { 3762 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3763 const PetscInt co = farr[fc * 2 + 1]; 3764 3765 for (i = 0; i < c; i += 2) 3766 if (pts[i] == cp) break; 3767 if (i == c) { 3768 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3769 pts[c++] = cp; 3770 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3771 } 3772 } 3773 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3774 } 3775 } 3776 *numPoints = c / 2; 3777 *points = pts; 3778 PetscFunctionReturn(PETSC_SUCCESS); 3779 } 3780 3781 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3782 { 3783 DMPolytopeType ct; 3784 PetscInt *closure, *fifo; 3785 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3786 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3787 PetscInt depth, maxSize; 3788 3789 PetscFunctionBeginHot; 3790 PetscCall(DMPlexGetDepth(dm, &depth)); 3791 if (depth == 1) { 3792 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3793 PetscFunctionReturn(PETSC_SUCCESS); 3794 } 3795 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3796 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3797 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3798 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3799 PetscFunctionReturn(PETSC_SUCCESS); 3800 } 3801 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3802 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3803 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3804 maxSize = PetscMax(coneSeries, supportSeries); 3805 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3806 if (*points) { 3807 closure = *points; 3808 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3809 closure[closureSize++] = p; 3810 closure[closureSize++] = ornt; 3811 fifo[fifoSize++] = p; 3812 fifo[fifoSize++] = ornt; 3813 fifo[fifoSize++] = ct; 3814 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3815 while (fifoSize - fifoStart) { 3816 const PetscInt q = fifo[fifoStart++]; 3817 const PetscInt o = fifo[fifoStart++]; 3818 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3819 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3820 const PetscInt *tmp, *tmpO = NULL; 3821 PetscInt tmpSize, t; 3822 3823 if (PetscDefined(USE_DEBUG)) { 3824 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3825 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); 3826 } 3827 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3828 for (t = 0; t < tmpSize; ++t) { 3829 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3830 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3831 const PetscInt cp = tmp[ip]; 3832 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3833 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3834 PetscInt c; 3835 3836 /* Check for duplicate */ 3837 for (c = 0; c < closureSize; c += 2) { 3838 if (closure[c] == cp) break; 3839 } 3840 if (c == closureSize) { 3841 closure[closureSize++] = cp; 3842 closure[closureSize++] = co; 3843 fifo[fifoSize++] = cp; 3844 fifo[fifoSize++] = co; 3845 fifo[fifoSize++] = ct; 3846 } 3847 } 3848 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3849 } 3850 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3851 if (numPoints) *numPoints = closureSize / 2; 3852 if (points) *points = closure; 3853 PetscFunctionReturn(PETSC_SUCCESS); 3854 } 3855 3856 /*@C 3857 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3858 3859 Not Collective 3860 3861 Input Parameters: 3862 + dm - The `DMPLEX` 3863 . p - The mesh point 3864 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 3865 3866 Input/Output Parameter: 3867 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3868 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 3869 3870 Output Parameter: 3871 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 3872 3873 Level: beginner 3874 3875 Note: 3876 If using internal storage (points is `NULL` on input), each call overwrites the last output. 3877 3878 Fortran Notes: 3879 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 3880 3881 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3882 @*/ 3883 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3884 { 3885 PetscFunctionBeginHot; 3886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3887 if (numPoints) PetscAssertPointer(numPoints, 4); 3888 if (points) PetscAssertPointer(points, 5); 3889 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3890 PetscFunctionReturn(PETSC_SUCCESS); 3891 } 3892 3893 /*@C 3894 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3895 3896 Not Collective 3897 3898 Input Parameters: 3899 + dm - The `DMPLEX` 3900 . p - The mesh point 3901 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 3902 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 3903 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3904 3905 Level: beginner 3906 3907 Note: 3908 If not using internal storage (points is not `NULL` on input), this call is unnecessary 3909 3910 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3911 @*/ 3912 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3913 { 3914 PetscFunctionBeginHot; 3915 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3916 if (numPoints) *numPoints = 0; 3917 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3918 PetscFunctionReturn(PETSC_SUCCESS); 3919 } 3920 3921 /*@ 3922 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3923 3924 Not Collective 3925 3926 Input Parameter: 3927 . dm - The `DMPLEX` 3928 3929 Output Parameters: 3930 + maxConeSize - The maximum number of in-edges 3931 - maxSupportSize - The maximum number of out-edges 3932 3933 Level: beginner 3934 3935 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3936 @*/ 3937 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3938 { 3939 DM_Plex *mesh = (DM_Plex *)dm->data; 3940 3941 PetscFunctionBegin; 3942 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3943 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3944 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3945 PetscFunctionReturn(PETSC_SUCCESS); 3946 } 3947 3948 PetscErrorCode DMSetUp_Plex(DM dm) 3949 { 3950 DM_Plex *mesh = (DM_Plex *)dm->data; 3951 PetscInt size, maxSupportSize; 3952 3953 PetscFunctionBegin; 3954 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3955 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3956 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3957 PetscCall(PetscMalloc1(size, &mesh->cones)); 3958 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3959 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3960 if (maxSupportSize) { 3961 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3962 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3963 PetscCall(PetscMalloc1(size, &mesh->supports)); 3964 } 3965 PetscFunctionReturn(PETSC_SUCCESS); 3966 } 3967 3968 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3969 { 3970 PetscFunctionBegin; 3971 if (subdm) PetscCall(DMClone(dm, subdm)); 3972 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3973 if (subdm) (*subdm)->useNatural = dm->useNatural; 3974 if (dm->useNatural && dm->sfMigration) { 3975 PetscSF sfNatural; 3976 3977 (*subdm)->sfMigration = dm->sfMigration; 3978 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3979 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3980 (*subdm)->sfNatural = sfNatural; 3981 } 3982 PetscFunctionReturn(PETSC_SUCCESS); 3983 } 3984 3985 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3986 { 3987 PetscInt i = 0; 3988 3989 PetscFunctionBegin; 3990 PetscCall(DMClone(dms[0], superdm)); 3991 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3992 (*superdm)->useNatural = PETSC_FALSE; 3993 for (i = 0; i < len; i++) { 3994 if (dms[i]->useNatural && dms[i]->sfMigration) { 3995 PetscSF sfNatural; 3996 3997 (*superdm)->sfMigration = dms[i]->sfMigration; 3998 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3999 (*superdm)->useNatural = PETSC_TRUE; 4000 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4001 (*superdm)->sfNatural = sfNatural; 4002 break; 4003 } 4004 } 4005 PetscFunctionReturn(PETSC_SUCCESS); 4006 } 4007 4008 /*@ 4009 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4010 4011 Not Collective 4012 4013 Input Parameter: 4014 . dm - The `DMPLEX` 4015 4016 Level: beginner 4017 4018 Note: 4019 This should be called after all calls to `DMPlexSetCone()` 4020 4021 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4022 @*/ 4023 PetscErrorCode DMPlexSymmetrize(DM dm) 4024 { 4025 DM_Plex *mesh = (DM_Plex *)dm->data; 4026 PetscInt *offsets; 4027 PetscInt supportSize; 4028 PetscInt pStart, pEnd, p; 4029 4030 PetscFunctionBegin; 4031 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4032 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4033 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4034 /* Calculate support sizes */ 4035 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4036 for (p = pStart; p < pEnd; ++p) { 4037 PetscInt dof, off, c; 4038 4039 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4040 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4041 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4042 } 4043 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4044 /* Calculate supports */ 4045 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4046 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4047 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4048 for (p = pStart; p < pEnd; ++p) { 4049 PetscInt dof, off, c; 4050 4051 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4052 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4053 for (c = off; c < off + dof; ++c) { 4054 const PetscInt q = mesh->cones[c]; 4055 PetscInt offS; 4056 4057 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4058 4059 mesh->supports[offS + offsets[q]] = p; 4060 ++offsets[q]; 4061 } 4062 } 4063 PetscCall(PetscFree(offsets)); 4064 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4065 PetscFunctionReturn(PETSC_SUCCESS); 4066 } 4067 4068 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4069 { 4070 IS stratumIS; 4071 4072 PetscFunctionBegin; 4073 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4074 if (PetscDefined(USE_DEBUG)) { 4075 PetscInt qStart, qEnd, numLevels, level; 4076 PetscBool overlap = PETSC_FALSE; 4077 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4078 for (level = 0; level < numLevels; level++) { 4079 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4080 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4081 overlap = PETSC_TRUE; 4082 break; 4083 } 4084 } 4085 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); 4086 } 4087 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4088 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4089 PetscCall(ISDestroy(&stratumIS)); 4090 PetscFunctionReturn(PETSC_SUCCESS); 4091 } 4092 4093 /*@ 4094 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4095 4096 Collective 4097 4098 Input Parameter: 4099 . dm - The `DMPLEX` 4100 4101 Level: beginner 4102 4103 Notes: 4104 The strata group all points of the same grade, and this function calculates the strata. This 4105 grade can be seen as the height (or depth) of the point in the DAG. 4106 4107 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4108 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4109 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4110 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4111 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4112 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4113 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4114 4115 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4116 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4117 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 4118 to interpolate only that one (e0), so that 4119 .vb 4120 cone(c0) = {e0, v2} 4121 cone(e0) = {v0, v1} 4122 .ve 4123 If `DMPlexStratify()` is run on this mesh, it will give depths 4124 .vb 4125 depth 0 = {v0, v1, v2} 4126 depth 1 = {e0, c0} 4127 .ve 4128 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4129 4130 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4131 4132 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4133 @*/ 4134 PetscErrorCode DMPlexStratify(DM dm) 4135 { 4136 DM_Plex *mesh = (DM_Plex *)dm->data; 4137 DMLabel label; 4138 PetscInt pStart, pEnd, p; 4139 PetscInt numRoots = 0, numLeaves = 0; 4140 4141 PetscFunctionBegin; 4142 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4143 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4144 4145 /* Create depth label */ 4146 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4147 PetscCall(DMCreateLabel(dm, "depth")); 4148 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4149 4150 { 4151 /* Initialize roots and count leaves */ 4152 PetscInt sMin = PETSC_MAX_INT; 4153 PetscInt sMax = PETSC_MIN_INT; 4154 PetscInt coneSize, supportSize; 4155 4156 for (p = pStart; p < pEnd; ++p) { 4157 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4158 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4159 if (!coneSize && supportSize) { 4160 sMin = PetscMin(p, sMin); 4161 sMax = PetscMax(p, sMax); 4162 ++numRoots; 4163 } else if (!supportSize && coneSize) { 4164 ++numLeaves; 4165 } else if (!supportSize && !coneSize) { 4166 /* Isolated points */ 4167 sMin = PetscMin(p, sMin); 4168 sMax = PetscMax(p, sMax); 4169 } 4170 } 4171 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4172 } 4173 4174 if (numRoots + numLeaves == (pEnd - pStart)) { 4175 PetscInt sMin = PETSC_MAX_INT; 4176 PetscInt sMax = PETSC_MIN_INT; 4177 PetscInt coneSize, supportSize; 4178 4179 for (p = pStart; p < pEnd; ++p) { 4180 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4181 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4182 if (!supportSize && coneSize) { 4183 sMin = PetscMin(p, sMin); 4184 sMax = PetscMax(p, sMax); 4185 } 4186 } 4187 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4188 } else { 4189 PetscInt level = 0; 4190 PetscInt qStart, qEnd, q; 4191 4192 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4193 while (qEnd > qStart) { 4194 PetscInt sMin = PETSC_MAX_INT; 4195 PetscInt sMax = PETSC_MIN_INT; 4196 4197 for (q = qStart; q < qEnd; ++q) { 4198 const PetscInt *support; 4199 PetscInt supportSize, s; 4200 4201 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4202 PetscCall(DMPlexGetSupport(dm, q, &support)); 4203 for (s = 0; s < supportSize; ++s) { 4204 sMin = PetscMin(support[s], sMin); 4205 sMax = PetscMax(support[s], sMax); 4206 } 4207 } 4208 PetscCall(DMLabelGetNumValues(label, &level)); 4209 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4210 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4211 } 4212 } 4213 { /* just in case there is an empty process */ 4214 PetscInt numValues, maxValues = 0, v; 4215 4216 PetscCall(DMLabelGetNumValues(label, &numValues)); 4217 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4218 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4219 } 4220 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4221 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4222 PetscFunctionReturn(PETSC_SUCCESS); 4223 } 4224 4225 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4226 { 4227 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4228 PetscInt dim, depth, pheight, coneSize; 4229 4230 PetscFunctionBeginHot; 4231 PetscCall(DMGetDimension(dm, &dim)); 4232 PetscCall(DMPlexGetDepth(dm, &depth)); 4233 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4234 pheight = depth - pdepth; 4235 if (depth <= 1) { 4236 switch (pdepth) { 4237 case 0: 4238 ct = DM_POLYTOPE_POINT; 4239 break; 4240 case 1: 4241 switch (coneSize) { 4242 case 2: 4243 ct = DM_POLYTOPE_SEGMENT; 4244 break; 4245 case 3: 4246 ct = DM_POLYTOPE_TRIANGLE; 4247 break; 4248 case 4: 4249 switch (dim) { 4250 case 2: 4251 ct = DM_POLYTOPE_QUADRILATERAL; 4252 break; 4253 case 3: 4254 ct = DM_POLYTOPE_TETRAHEDRON; 4255 break; 4256 default: 4257 break; 4258 } 4259 break; 4260 case 5: 4261 ct = DM_POLYTOPE_PYRAMID; 4262 break; 4263 case 6: 4264 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4265 break; 4266 case 8: 4267 ct = DM_POLYTOPE_HEXAHEDRON; 4268 break; 4269 default: 4270 break; 4271 } 4272 } 4273 } else { 4274 if (pdepth == 0) { 4275 ct = DM_POLYTOPE_POINT; 4276 } else if (pheight == 0) { 4277 switch (dim) { 4278 case 1: 4279 switch (coneSize) { 4280 case 2: 4281 ct = DM_POLYTOPE_SEGMENT; 4282 break; 4283 default: 4284 break; 4285 } 4286 break; 4287 case 2: 4288 switch (coneSize) { 4289 case 3: 4290 ct = DM_POLYTOPE_TRIANGLE; 4291 break; 4292 case 4: 4293 ct = DM_POLYTOPE_QUADRILATERAL; 4294 break; 4295 default: 4296 break; 4297 } 4298 break; 4299 case 3: 4300 switch (coneSize) { 4301 case 4: 4302 ct = DM_POLYTOPE_TETRAHEDRON; 4303 break; 4304 case 5: { 4305 const PetscInt *cone; 4306 PetscInt faceConeSize; 4307 4308 PetscCall(DMPlexGetCone(dm, p, &cone)); 4309 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4310 switch (faceConeSize) { 4311 case 3: 4312 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4313 break; 4314 case 4: 4315 ct = DM_POLYTOPE_PYRAMID; 4316 break; 4317 } 4318 } break; 4319 case 6: 4320 ct = DM_POLYTOPE_HEXAHEDRON; 4321 break; 4322 default: 4323 break; 4324 } 4325 break; 4326 default: 4327 break; 4328 } 4329 } else if (pheight > 0) { 4330 switch (coneSize) { 4331 case 2: 4332 ct = DM_POLYTOPE_SEGMENT; 4333 break; 4334 case 3: 4335 ct = DM_POLYTOPE_TRIANGLE; 4336 break; 4337 case 4: 4338 ct = DM_POLYTOPE_QUADRILATERAL; 4339 break; 4340 default: 4341 break; 4342 } 4343 } 4344 } 4345 *pt = ct; 4346 PetscFunctionReturn(PETSC_SUCCESS); 4347 } 4348 4349 /*@ 4350 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4351 4352 Collective 4353 4354 Input Parameter: 4355 . dm - The `DMPLEX` 4356 4357 Level: developer 4358 4359 Note: 4360 This function is normally called automatically when a cell type is requested. It creates an 4361 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4362 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4363 4364 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4365 4366 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4367 @*/ 4368 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4369 { 4370 DM_Plex *mesh; 4371 DMLabel ctLabel; 4372 PetscInt pStart, pEnd, p; 4373 4374 PetscFunctionBegin; 4375 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4376 mesh = (DM_Plex *)dm->data; 4377 PetscCall(DMCreateLabel(dm, "celltype")); 4378 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4379 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4380 PetscCall(PetscFree(mesh->cellTypes)); 4381 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4382 for (p = pStart; p < pEnd; ++p) { 4383 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4384 PetscInt pdepth; 4385 4386 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4387 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4388 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4389 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4390 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4391 } 4392 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4393 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4394 PetscFunctionReturn(PETSC_SUCCESS); 4395 } 4396 4397 /*@C 4398 DMPlexGetJoin - Get an array for the join of the set of points 4399 4400 Not Collective 4401 4402 Input Parameters: 4403 + dm - The `DMPLEX` object 4404 . numPoints - The number of input points for the join 4405 - points - The input points 4406 4407 Output Parameters: 4408 + numCoveredPoints - The number of points in the join 4409 - coveredPoints - The points in the join 4410 4411 Level: intermediate 4412 4413 Note: 4414 Currently, this is restricted to a single level join 4415 4416 Fortran Notes: 4417 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4418 4419 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4420 @*/ 4421 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4422 { 4423 DM_Plex *mesh = (DM_Plex *)dm->data; 4424 PetscInt *join[2]; 4425 PetscInt joinSize, i = 0; 4426 PetscInt dof, off, p, c, m; 4427 PetscInt maxSupportSize; 4428 4429 PetscFunctionBegin; 4430 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4431 PetscAssertPointer(points, 3); 4432 PetscAssertPointer(numCoveredPoints, 4); 4433 PetscAssertPointer(coveredPoints, 5); 4434 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4435 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4436 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4437 /* Copy in support of first point */ 4438 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4439 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4440 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4441 /* Check each successive support */ 4442 for (p = 1; p < numPoints; ++p) { 4443 PetscInt newJoinSize = 0; 4444 4445 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4446 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4447 for (c = 0; c < dof; ++c) { 4448 const PetscInt point = mesh->supports[off + c]; 4449 4450 for (m = 0; m < joinSize; ++m) { 4451 if (point == join[i][m]) { 4452 join[1 - i][newJoinSize++] = point; 4453 break; 4454 } 4455 } 4456 } 4457 joinSize = newJoinSize; 4458 i = 1 - i; 4459 } 4460 *numCoveredPoints = joinSize; 4461 *coveredPoints = join[i]; 4462 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4463 PetscFunctionReturn(PETSC_SUCCESS); 4464 } 4465 4466 /*@C 4467 DMPlexRestoreJoin - Restore an array for the join of the set of points 4468 4469 Not Collective 4470 4471 Input Parameters: 4472 + dm - The `DMPLEX` object 4473 . numPoints - The number of input points for the join 4474 - points - The input points 4475 4476 Output Parameters: 4477 + numCoveredPoints - The number of points in the join 4478 - coveredPoints - The points in the join 4479 4480 Level: intermediate 4481 4482 Fortran Notes: 4483 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4484 4485 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4486 @*/ 4487 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4488 { 4489 PetscFunctionBegin; 4490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4491 if (points) PetscAssertPointer(points, 3); 4492 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4493 PetscAssertPointer(coveredPoints, 5); 4494 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4495 if (numCoveredPoints) *numCoveredPoints = 0; 4496 PetscFunctionReturn(PETSC_SUCCESS); 4497 } 4498 4499 /*@C 4500 DMPlexGetFullJoin - Get an array for the join of the set of points 4501 4502 Not Collective 4503 4504 Input Parameters: 4505 + dm - The `DMPLEX` object 4506 . numPoints - The number of input points for the join 4507 - points - The input points 4508 4509 Output Parameters: 4510 + numCoveredPoints - The number of points in the join 4511 - coveredPoints - The points in the join 4512 4513 Level: intermediate 4514 4515 Fortran Notes: 4516 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4517 4518 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4519 @*/ 4520 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4521 { 4522 PetscInt *offsets, **closures; 4523 PetscInt *join[2]; 4524 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4525 PetscInt p, d, c, m, ms; 4526 4527 PetscFunctionBegin; 4528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4529 PetscAssertPointer(points, 3); 4530 PetscAssertPointer(numCoveredPoints, 4); 4531 PetscAssertPointer(coveredPoints, 5); 4532 4533 PetscCall(DMPlexGetDepth(dm, &depth)); 4534 PetscCall(PetscCalloc1(numPoints, &closures)); 4535 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4536 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4537 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4538 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4539 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4540 4541 for (p = 0; p < numPoints; ++p) { 4542 PetscInt closureSize; 4543 4544 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4545 4546 offsets[p * (depth + 2) + 0] = 0; 4547 for (d = 0; d < depth + 1; ++d) { 4548 PetscInt pStart, pEnd, i; 4549 4550 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4551 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4552 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4553 offsets[p * (depth + 2) + d + 1] = i; 4554 break; 4555 } 4556 } 4557 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4558 } 4559 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); 4560 } 4561 for (d = 0; d < depth + 1; ++d) { 4562 PetscInt dof; 4563 4564 /* Copy in support of first point */ 4565 dof = offsets[d + 1] - offsets[d]; 4566 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4567 /* Check each successive cone */ 4568 for (p = 1; p < numPoints && joinSize; ++p) { 4569 PetscInt newJoinSize = 0; 4570 4571 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4572 for (c = 0; c < dof; ++c) { 4573 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4574 4575 for (m = 0; m < joinSize; ++m) { 4576 if (point == join[i][m]) { 4577 join[1 - i][newJoinSize++] = point; 4578 break; 4579 } 4580 } 4581 } 4582 joinSize = newJoinSize; 4583 i = 1 - i; 4584 } 4585 if (joinSize) break; 4586 } 4587 *numCoveredPoints = joinSize; 4588 *coveredPoints = join[i]; 4589 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4590 PetscCall(PetscFree(closures)); 4591 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4592 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4593 PetscFunctionReturn(PETSC_SUCCESS); 4594 } 4595 4596 /*@C 4597 DMPlexGetMeet - Get 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 + numCoveringPoints - The number of points in the meet 4608 - coveringPoints - The points in the meet 4609 4610 Level: intermediate 4611 4612 Note: 4613 Currently, this is restricted to a single level meet 4614 4615 Fortran Notes: 4616 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4617 4618 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4619 @*/ 4620 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4621 { 4622 DM_Plex *mesh = (DM_Plex *)dm->data; 4623 PetscInt *meet[2]; 4624 PetscInt meetSize, i = 0; 4625 PetscInt dof, off, p, c, m; 4626 PetscInt maxConeSize; 4627 4628 PetscFunctionBegin; 4629 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4630 PetscAssertPointer(points, 3); 4631 PetscAssertPointer(numCoveringPoints, 4); 4632 PetscAssertPointer(coveringPoints, 5); 4633 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4634 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4635 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4636 /* Copy in cone of first point */ 4637 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4638 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4639 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4640 /* Check each successive cone */ 4641 for (p = 1; p < numPoints; ++p) { 4642 PetscInt newMeetSize = 0; 4643 4644 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4645 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4646 for (c = 0; c < dof; ++c) { 4647 const PetscInt point = mesh->cones[off + c]; 4648 4649 for (m = 0; m < meetSize; ++m) { 4650 if (point == meet[i][m]) { 4651 meet[1 - i][newMeetSize++] = point; 4652 break; 4653 } 4654 } 4655 } 4656 meetSize = newMeetSize; 4657 i = 1 - i; 4658 } 4659 *numCoveringPoints = meetSize; 4660 *coveringPoints = meet[i]; 4661 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4662 PetscFunctionReturn(PETSC_SUCCESS); 4663 } 4664 4665 /*@C 4666 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4667 4668 Not Collective 4669 4670 Input Parameters: 4671 + dm - The `DMPLEX` object 4672 . numPoints - The number of input points for the meet 4673 - points - The input points 4674 4675 Output Parameters: 4676 + numCoveredPoints - The number of points in the meet 4677 - coveredPoints - The points in the meet 4678 4679 Level: intermediate 4680 4681 Fortran Notes: 4682 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4683 4684 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4685 @*/ 4686 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4687 { 4688 PetscFunctionBegin; 4689 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4690 if (points) PetscAssertPointer(points, 3); 4691 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4692 PetscAssertPointer(coveredPoints, 5); 4693 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4694 if (numCoveredPoints) *numCoveredPoints = 0; 4695 PetscFunctionReturn(PETSC_SUCCESS); 4696 } 4697 4698 /*@C 4699 DMPlexGetFullMeet - Get an array for the meet of the set of points 4700 4701 Not Collective 4702 4703 Input Parameters: 4704 + dm - The `DMPLEX` object 4705 . numPoints - The number of input points for the meet 4706 - points - The input points 4707 4708 Output Parameters: 4709 + numCoveredPoints - The number of points in the meet 4710 - coveredPoints - The points in the meet 4711 4712 Level: intermediate 4713 4714 Fortran Notes: 4715 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4716 4717 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4718 @*/ 4719 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4720 { 4721 PetscInt *offsets, **closures; 4722 PetscInt *meet[2]; 4723 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4724 PetscInt p, h, c, m, mc; 4725 4726 PetscFunctionBegin; 4727 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4728 PetscAssertPointer(points, 3); 4729 PetscAssertPointer(numCoveredPoints, 4); 4730 PetscAssertPointer(coveredPoints, 5); 4731 4732 PetscCall(DMPlexGetDepth(dm, &height)); 4733 PetscCall(PetscMalloc1(numPoints, &closures)); 4734 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4735 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4736 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4737 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4738 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4739 4740 for (p = 0; p < numPoints; ++p) { 4741 PetscInt closureSize; 4742 4743 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4744 4745 offsets[p * (height + 2) + 0] = 0; 4746 for (h = 0; h < height + 1; ++h) { 4747 PetscInt pStart, pEnd, i; 4748 4749 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4750 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4751 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4752 offsets[p * (height + 2) + h + 1] = i; 4753 break; 4754 } 4755 } 4756 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4757 } 4758 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); 4759 } 4760 for (h = 0; h < height + 1; ++h) { 4761 PetscInt dof; 4762 4763 /* Copy in cone of first point */ 4764 dof = offsets[h + 1] - offsets[h]; 4765 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4766 /* Check each successive cone */ 4767 for (p = 1; p < numPoints && meetSize; ++p) { 4768 PetscInt newMeetSize = 0; 4769 4770 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4771 for (c = 0; c < dof; ++c) { 4772 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4773 4774 for (m = 0; m < meetSize; ++m) { 4775 if (point == meet[i][m]) { 4776 meet[1 - i][newMeetSize++] = point; 4777 break; 4778 } 4779 } 4780 } 4781 meetSize = newMeetSize; 4782 i = 1 - i; 4783 } 4784 if (meetSize) break; 4785 } 4786 *numCoveredPoints = meetSize; 4787 *coveredPoints = meet[i]; 4788 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4789 PetscCall(PetscFree(closures)); 4790 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4791 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4792 PetscFunctionReturn(PETSC_SUCCESS); 4793 } 4794 4795 /*@C 4796 DMPlexEqual - Determine if two `DM` have the same topology 4797 4798 Not Collective 4799 4800 Input Parameters: 4801 + dmA - A `DMPLEX` object 4802 - dmB - A `DMPLEX` object 4803 4804 Output Parameter: 4805 . equal - `PETSC_TRUE` if the topologies are identical 4806 4807 Level: intermediate 4808 4809 Note: 4810 We are not solving graph isomorphism, so we do not permute. 4811 4812 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4813 @*/ 4814 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4815 { 4816 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4817 4818 PetscFunctionBegin; 4819 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4820 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4821 PetscAssertPointer(equal, 3); 4822 4823 *equal = PETSC_FALSE; 4824 PetscCall(DMPlexGetDepth(dmA, &depth)); 4825 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4826 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 4827 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4828 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4829 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 4830 for (p = pStart; p < pEnd; ++p) { 4831 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4832 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4833 4834 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4835 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4836 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4837 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4838 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4839 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4840 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4841 for (c = 0; c < coneSize; ++c) { 4842 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4843 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4844 } 4845 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4846 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4847 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4848 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4849 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4850 for (s = 0; s < supportSize; ++s) { 4851 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 4852 } 4853 } 4854 *equal = PETSC_TRUE; 4855 PetscFunctionReturn(PETSC_SUCCESS); 4856 } 4857 4858 /*@C 4859 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4860 4861 Not Collective 4862 4863 Input Parameters: 4864 + dm - The `DMPLEX` 4865 . cellDim - The cell dimension 4866 - numCorners - The number of vertices on a cell 4867 4868 Output Parameter: 4869 . numFaceVertices - The number of vertices on a face 4870 4871 Level: developer 4872 4873 Note: 4874 Of course this can only work for a restricted set of symmetric shapes 4875 4876 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4877 @*/ 4878 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4879 { 4880 MPI_Comm comm; 4881 4882 PetscFunctionBegin; 4883 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4884 PetscAssertPointer(numFaceVertices, 4); 4885 switch (cellDim) { 4886 case 0: 4887 *numFaceVertices = 0; 4888 break; 4889 case 1: 4890 *numFaceVertices = 1; 4891 break; 4892 case 2: 4893 switch (numCorners) { 4894 case 3: /* triangle */ 4895 *numFaceVertices = 2; /* Edge has 2 vertices */ 4896 break; 4897 case 4: /* quadrilateral */ 4898 *numFaceVertices = 2; /* Edge has 2 vertices */ 4899 break; 4900 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4901 *numFaceVertices = 3; /* Edge has 3 vertices */ 4902 break; 4903 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4904 *numFaceVertices = 3; /* Edge has 3 vertices */ 4905 break; 4906 default: 4907 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4908 } 4909 break; 4910 case 3: 4911 switch (numCorners) { 4912 case 4: /* tetradehdron */ 4913 *numFaceVertices = 3; /* Face has 3 vertices */ 4914 break; 4915 case 6: /* tet cohesive cells */ 4916 *numFaceVertices = 4; /* Face has 4 vertices */ 4917 break; 4918 case 8: /* hexahedron */ 4919 *numFaceVertices = 4; /* Face has 4 vertices */ 4920 break; 4921 case 9: /* tet cohesive Lagrange cells */ 4922 *numFaceVertices = 6; /* Face has 6 vertices */ 4923 break; 4924 case 10: /* quadratic tetrahedron */ 4925 *numFaceVertices = 6; /* Face has 6 vertices */ 4926 break; 4927 case 12: /* hex cohesive Lagrange cells */ 4928 *numFaceVertices = 6; /* Face has 6 vertices */ 4929 break; 4930 case 18: /* quadratic tet cohesive Lagrange cells */ 4931 *numFaceVertices = 6; /* Face has 6 vertices */ 4932 break; 4933 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4934 *numFaceVertices = 9; /* Face has 9 vertices */ 4935 break; 4936 default: 4937 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4938 } 4939 break; 4940 default: 4941 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4942 } 4943 PetscFunctionReturn(PETSC_SUCCESS); 4944 } 4945 4946 /*@ 4947 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 4948 4949 Not Collective 4950 4951 Input Parameter: 4952 . dm - The `DMPLEX` object 4953 4954 Output Parameter: 4955 . depthLabel - The `DMLabel` recording point depth 4956 4957 Level: developer 4958 4959 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4960 @*/ 4961 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4962 { 4963 PetscFunctionBegin; 4964 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4965 PetscAssertPointer(depthLabel, 2); 4966 *depthLabel = dm->depthLabel; 4967 PetscFunctionReturn(PETSC_SUCCESS); 4968 } 4969 4970 /*@ 4971 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4972 4973 Not Collective 4974 4975 Input Parameter: 4976 . dm - The `DMPLEX` object 4977 4978 Output Parameter: 4979 . depth - The number of strata (breadth first levels) in the DAG 4980 4981 Level: developer 4982 4983 Notes: 4984 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 4985 4986 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 4987 4988 An empty mesh gives -1. 4989 4990 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4991 @*/ 4992 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4993 { 4994 DM_Plex *mesh = (DM_Plex *)dm->data; 4995 DMLabel label; 4996 PetscInt d = 0; 4997 4998 PetscFunctionBegin; 4999 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5000 PetscAssertPointer(depth, 2); 5001 if (mesh->tr) { 5002 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5003 } else { 5004 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5005 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5006 *depth = d - 1; 5007 } 5008 PetscFunctionReturn(PETSC_SUCCESS); 5009 } 5010 5011 /*@ 5012 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5013 5014 Not Collective 5015 5016 Input Parameters: 5017 + dm - The `DMPLEX` object 5018 - depth - The requested depth 5019 5020 Output Parameters: 5021 + start - The first point at this `depth` 5022 - end - One beyond the last point at this `depth` 5023 5024 Level: developer 5025 5026 Notes: 5027 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5028 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5029 higher dimension, e.g., "edges". 5030 5031 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5032 @*/ 5033 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5034 { 5035 DM_Plex *mesh = (DM_Plex *)dm->data; 5036 DMLabel label; 5037 PetscInt pStart, pEnd; 5038 5039 PetscFunctionBegin; 5040 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5041 if (start) { 5042 PetscAssertPointer(start, 3); 5043 *start = 0; 5044 } 5045 if (end) { 5046 PetscAssertPointer(end, 4); 5047 *end = 0; 5048 } 5049 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5050 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5051 if (depth < 0) { 5052 if (start) *start = pStart; 5053 if (end) *end = pEnd; 5054 PetscFunctionReturn(PETSC_SUCCESS); 5055 } 5056 if (mesh->tr) { 5057 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5058 } else { 5059 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5060 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5061 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5062 } 5063 PetscFunctionReturn(PETSC_SUCCESS); 5064 } 5065 5066 /*@ 5067 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5068 5069 Not Collective 5070 5071 Input Parameters: 5072 + dm - The `DMPLEX` object 5073 - height - The requested height 5074 5075 Output Parameters: 5076 + start - The first point at this `height` 5077 - end - One beyond the last point at this `height` 5078 5079 Level: developer 5080 5081 Notes: 5082 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5083 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5084 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5085 5086 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5087 @*/ 5088 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5089 { 5090 DMLabel label; 5091 PetscInt depth, pStart, pEnd; 5092 5093 PetscFunctionBegin; 5094 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5095 if (start) { 5096 PetscAssertPointer(start, 3); 5097 *start = 0; 5098 } 5099 if (end) { 5100 PetscAssertPointer(end, 4); 5101 *end = 0; 5102 } 5103 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5104 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5105 if (height < 0) { 5106 if (start) *start = pStart; 5107 if (end) *end = pEnd; 5108 PetscFunctionReturn(PETSC_SUCCESS); 5109 } 5110 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5111 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5112 else PetscCall(DMGetDimension(dm, &depth)); 5113 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5114 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5115 PetscFunctionReturn(PETSC_SUCCESS); 5116 } 5117 5118 /*@ 5119 DMPlexGetPointDepth - Get the `depth` of a given point 5120 5121 Not Collective 5122 5123 Input Parameters: 5124 + dm - The `DMPLEX` object 5125 - point - The point 5126 5127 Output Parameter: 5128 . depth - The depth of the `point` 5129 5130 Level: intermediate 5131 5132 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5133 @*/ 5134 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5135 { 5136 PetscFunctionBegin; 5137 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5138 PetscAssertPointer(depth, 3); 5139 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5140 PetscFunctionReturn(PETSC_SUCCESS); 5141 } 5142 5143 /*@ 5144 DMPlexGetPointHeight - Get the `height` of a given point 5145 5146 Not Collective 5147 5148 Input Parameters: 5149 + dm - The `DMPLEX` object 5150 - point - The point 5151 5152 Output Parameter: 5153 . height - The height of the `point` 5154 5155 Level: intermediate 5156 5157 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5158 @*/ 5159 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5160 { 5161 PetscInt n, pDepth; 5162 5163 PetscFunctionBegin; 5164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5165 PetscAssertPointer(height, 3); 5166 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5167 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5168 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5169 PetscFunctionReturn(PETSC_SUCCESS); 5170 } 5171 5172 /*@ 5173 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5174 5175 Not Collective 5176 5177 Input Parameter: 5178 . dm - The `DMPLEX` object 5179 5180 Output Parameter: 5181 . celltypeLabel - The `DMLabel` recording cell polytope type 5182 5183 Level: developer 5184 5185 Note: 5186 This function will trigger automatica computation of cell types. This can be disabled by calling 5187 `DMCreateLabel`(dm, "celltype") beforehand. 5188 5189 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5190 @*/ 5191 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5192 { 5193 PetscFunctionBegin; 5194 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5195 PetscAssertPointer(celltypeLabel, 2); 5196 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5197 *celltypeLabel = dm->celltypeLabel; 5198 PetscFunctionReturn(PETSC_SUCCESS); 5199 } 5200 5201 /*@ 5202 DMPlexGetCellType - Get the polytope type of a given cell 5203 5204 Not Collective 5205 5206 Input Parameters: 5207 + dm - The `DMPLEX` object 5208 - cell - The cell 5209 5210 Output Parameter: 5211 . celltype - The polytope type of the cell 5212 5213 Level: intermediate 5214 5215 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5216 @*/ 5217 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5218 { 5219 DM_Plex *mesh = (DM_Plex *)dm->data; 5220 DMLabel label; 5221 PetscInt ct; 5222 5223 PetscFunctionBegin; 5224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5225 PetscAssertPointer(celltype, 3); 5226 if (mesh->tr) { 5227 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5228 } else { 5229 PetscInt pStart, pEnd; 5230 5231 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5232 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5233 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5234 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5235 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5236 for (PetscInt p = pStart; p < pEnd; p++) { 5237 PetscCall(DMLabelGetValue(label, p, &ct)); 5238 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5239 } 5240 } 5241 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5242 if (PetscDefined(USE_DEBUG)) { 5243 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5244 PetscCall(DMLabelGetValue(label, cell, &ct)); 5245 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5246 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5247 } 5248 } 5249 PetscFunctionReturn(PETSC_SUCCESS); 5250 } 5251 5252 /*@ 5253 DMPlexSetCellType - Set the polytope type of a given cell 5254 5255 Not Collective 5256 5257 Input Parameters: 5258 + dm - The `DMPLEX` object 5259 . cell - The cell 5260 - celltype - The polytope type of the cell 5261 5262 Level: advanced 5263 5264 Note: 5265 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5266 is executed. This function will override the computed type. However, if automatic classification will not succeed 5267 and a user wants to manually specify all types, the classification must be disabled by calling 5268 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5269 5270 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5271 @*/ 5272 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5273 { 5274 DM_Plex *mesh = (DM_Plex *)dm->data; 5275 DMLabel label; 5276 PetscInt pStart, pEnd; 5277 5278 PetscFunctionBegin; 5279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5280 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5281 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5282 PetscCall(DMLabelSetValue(label, cell, celltype)); 5283 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5284 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5285 PetscFunctionReturn(PETSC_SUCCESS); 5286 } 5287 5288 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5289 { 5290 PetscSection section, s; 5291 Mat m; 5292 PetscInt maxHeight; 5293 const char *prefix; 5294 5295 PetscFunctionBegin; 5296 PetscCall(DMClone(dm, cdm)); 5297 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5298 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5299 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5300 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5301 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5302 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5303 PetscCall(DMSetLocalSection(*cdm, section)); 5304 PetscCall(PetscSectionDestroy(§ion)); 5305 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5306 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5307 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5308 PetscCall(PetscSectionDestroy(&s)); 5309 PetscCall(MatDestroy(&m)); 5310 5311 PetscCall(DMSetNumFields(*cdm, 1)); 5312 PetscCall(DMCreateDS(*cdm)); 5313 (*cdm)->cloneOpts = PETSC_TRUE; 5314 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5315 PetscFunctionReturn(PETSC_SUCCESS); 5316 } 5317 5318 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5319 { 5320 Vec coordsLocal, cellCoordsLocal; 5321 DM coordsDM, cellCoordsDM; 5322 5323 PetscFunctionBegin; 5324 *field = NULL; 5325 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5326 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5327 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5328 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5329 if (coordsLocal && coordsDM) { 5330 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5331 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5332 } 5333 PetscFunctionReturn(PETSC_SUCCESS); 5334 } 5335 5336 /*@C 5337 DMPlexGetConeSection - Return a section which describes the layout of cone data 5338 5339 Not Collective 5340 5341 Input Parameter: 5342 . dm - The `DMPLEX` object 5343 5344 Output Parameter: 5345 . section - The `PetscSection` object 5346 5347 Level: developer 5348 5349 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5350 @*/ 5351 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5352 { 5353 DM_Plex *mesh = (DM_Plex *)dm->data; 5354 5355 PetscFunctionBegin; 5356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5357 if (section) *section = mesh->coneSection; 5358 PetscFunctionReturn(PETSC_SUCCESS); 5359 } 5360 5361 /*@C 5362 DMPlexGetSupportSection - Return a section which describes the layout of support data 5363 5364 Not Collective 5365 5366 Input Parameter: 5367 . dm - The `DMPLEX` object 5368 5369 Output Parameter: 5370 . section - The `PetscSection` object 5371 5372 Level: developer 5373 5374 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5375 @*/ 5376 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5377 { 5378 DM_Plex *mesh = (DM_Plex *)dm->data; 5379 5380 PetscFunctionBegin; 5381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5382 if (section) *section = mesh->supportSection; 5383 PetscFunctionReturn(PETSC_SUCCESS); 5384 } 5385 5386 /*@C 5387 DMPlexGetCones - Return cone data 5388 5389 Not Collective 5390 5391 Input Parameter: 5392 . dm - The `DMPLEX` object 5393 5394 Output Parameter: 5395 . cones - The cone for each point 5396 5397 Level: developer 5398 5399 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5400 @*/ 5401 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5402 { 5403 DM_Plex *mesh = (DM_Plex *)dm->data; 5404 5405 PetscFunctionBegin; 5406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5407 if (cones) *cones = mesh->cones; 5408 PetscFunctionReturn(PETSC_SUCCESS); 5409 } 5410 5411 /*@C 5412 DMPlexGetConeOrientations - Return cone orientation data 5413 5414 Not Collective 5415 5416 Input Parameter: 5417 . dm - The `DMPLEX` object 5418 5419 Output Parameter: 5420 . coneOrientations - The array of cone orientations for all points 5421 5422 Level: developer 5423 5424 Notes: 5425 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5426 5427 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5428 5429 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5430 @*/ 5431 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5432 { 5433 DM_Plex *mesh = (DM_Plex *)dm->data; 5434 5435 PetscFunctionBegin; 5436 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5437 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5438 PetscFunctionReturn(PETSC_SUCCESS); 5439 } 5440 5441 /******************************** FEM Support **********************************/ 5442 5443 /* 5444 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5445 representing a line in the section. 5446 */ 5447 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5448 { 5449 PetscFunctionBeginHot; 5450 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5451 if (line < 0) { 5452 *k = 0; 5453 *Nc = 0; 5454 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5455 *k = 1; 5456 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5457 /* An order k SEM disc has k-1 dofs on an edge */ 5458 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5459 *k = *k / *Nc + 1; 5460 } 5461 PetscFunctionReturn(PETSC_SUCCESS); 5462 } 5463 5464 /*@ 5465 5466 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5467 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5468 section provided (or the section of the `DM`). 5469 5470 Input Parameters: 5471 + dm - The `DM` 5472 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5473 - section - The `PetscSection` to reorder, or `NULL` for the default section 5474 5475 Example: 5476 A typical interpolated single-quad mesh might order points as 5477 .vb 5478 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5479 5480 v4 -- e6 -- v3 5481 | | 5482 e7 c0 e8 5483 | | 5484 v1 -- e5 -- v2 5485 .ve 5486 5487 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5488 dofs in the order of points, e.g., 5489 .vb 5490 c0 -> [0,1,2,3] 5491 v1 -> [4] 5492 ... 5493 e5 -> [8, 9] 5494 .ve 5495 5496 which corresponds to the dofs 5497 .vb 5498 6 10 11 7 5499 13 2 3 15 5500 12 0 1 14 5501 4 8 9 5 5502 .ve 5503 5504 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5505 .vb 5506 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5507 .ve 5508 5509 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5510 .vb 5511 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5512 .ve 5513 5514 Level: developer 5515 5516 Notes: 5517 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5518 degree of the basis. 5519 5520 This is required to run with libCEED. 5521 5522 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5523 @*/ 5524 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5525 { 5526 DMLabel label; 5527 PetscInt dim, depth = -1, eStart = -1, Nf; 5528 PetscBool vertexchart; 5529 5530 PetscFunctionBegin; 5531 PetscCall(DMGetDimension(dm, &dim)); 5532 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5533 if (point < 0) { 5534 PetscInt sStart, sEnd; 5535 5536 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5537 point = sEnd - sStart ? sStart : point; 5538 } 5539 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5540 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5541 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5542 if (depth == 1) { 5543 eStart = point; 5544 } else if (depth == dim) { 5545 const PetscInt *cone; 5546 5547 PetscCall(DMPlexGetCone(dm, point, &cone)); 5548 if (dim == 2) eStart = cone[0]; 5549 else if (dim == 3) { 5550 const PetscInt *cone2; 5551 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5552 eStart = cone2[0]; 5553 } 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); 5554 } 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); 5555 { /* Determine whether the chart covers all points or just vertices. */ 5556 PetscInt pStart, pEnd, cStart, cEnd; 5557 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5558 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5559 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5560 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5561 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5562 } 5563 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5564 for (PetscInt d = 1; d <= dim; d++) { 5565 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5566 PetscInt *perm; 5567 5568 for (f = 0; f < Nf; ++f) { 5569 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5570 size += PetscPowInt(k + 1, d) * Nc; 5571 } 5572 PetscCall(PetscMalloc1(size, &perm)); 5573 for (f = 0; f < Nf; ++f) { 5574 switch (d) { 5575 case 1: 5576 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5577 /* 5578 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5579 We want [ vtx0; edge of length k-1; vtx1 ] 5580 */ 5581 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5582 for (i = 0; i < k - 1; i++) 5583 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5584 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5585 foffset = offset; 5586 break; 5587 case 2: 5588 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5589 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5590 /* The SEM order is 5591 5592 v_lb, {e_b}, v_rb, 5593 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5594 v_lt, reverse {e_t}, v_rt 5595 */ 5596 { 5597 const PetscInt of = 0; 5598 const PetscInt oeb = of + PetscSqr(k - 1); 5599 const PetscInt oer = oeb + (k - 1); 5600 const PetscInt oet = oer + (k - 1); 5601 const PetscInt oel = oet + (k - 1); 5602 const PetscInt ovlb = oel + (k - 1); 5603 const PetscInt ovrb = ovlb + 1; 5604 const PetscInt ovrt = ovrb + 1; 5605 const PetscInt ovlt = ovrt + 1; 5606 PetscInt o; 5607 5608 /* bottom */ 5609 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5610 for (o = oeb; o < oer; ++o) 5611 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5612 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5613 /* middle */ 5614 for (i = 0; i < k - 1; ++i) { 5615 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5616 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5617 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5618 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5619 } 5620 /* top */ 5621 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5622 for (o = oel - 1; o >= oet; --o) 5623 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5624 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5625 foffset = offset; 5626 } 5627 break; 5628 case 3: 5629 /* The original hex closure is 5630 5631 {c, 5632 f_b, f_t, f_f, f_b, f_r, f_l, 5633 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5634 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5635 */ 5636 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5637 /* The SEM order is 5638 Bottom Slice 5639 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5640 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5641 v_blb, {e_bb}, v_brb, 5642 5643 Middle Slice (j) 5644 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5645 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5646 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5647 5648 Top Slice 5649 v_tlf, {e_tf}, v_trf, 5650 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5651 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5652 */ 5653 { 5654 const PetscInt oc = 0; 5655 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5656 const PetscInt oft = ofb + PetscSqr(k - 1); 5657 const PetscInt off = oft + PetscSqr(k - 1); 5658 const PetscInt ofk = off + PetscSqr(k - 1); 5659 const PetscInt ofr = ofk + PetscSqr(k - 1); 5660 const PetscInt ofl = ofr + PetscSqr(k - 1); 5661 const PetscInt oebl = ofl + PetscSqr(k - 1); 5662 const PetscInt oebb = oebl + (k - 1); 5663 const PetscInt oebr = oebb + (k - 1); 5664 const PetscInt oebf = oebr + (k - 1); 5665 const PetscInt oetf = oebf + (k - 1); 5666 const PetscInt oetr = oetf + (k - 1); 5667 const PetscInt oetb = oetr + (k - 1); 5668 const PetscInt oetl = oetb + (k - 1); 5669 const PetscInt oerf = oetl + (k - 1); 5670 const PetscInt oelf = oerf + (k - 1); 5671 const PetscInt oelb = oelf + (k - 1); 5672 const PetscInt oerb = oelb + (k - 1); 5673 const PetscInt ovblf = oerb + (k - 1); 5674 const PetscInt ovblb = ovblf + 1; 5675 const PetscInt ovbrb = ovblb + 1; 5676 const PetscInt ovbrf = ovbrb + 1; 5677 const PetscInt ovtlf = ovbrf + 1; 5678 const PetscInt ovtrf = ovtlf + 1; 5679 const PetscInt ovtrb = ovtrf + 1; 5680 const PetscInt ovtlb = ovtrb + 1; 5681 PetscInt o, n; 5682 5683 /* Bottom Slice */ 5684 /* bottom */ 5685 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5686 for (o = oetf - 1; o >= oebf; --o) 5687 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5688 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5689 /* middle */ 5690 for (i = 0; i < k - 1; ++i) { 5691 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5692 for (n = 0; n < k - 1; ++n) { 5693 o = ofb + n * (k - 1) + i; 5694 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5695 } 5696 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5697 } 5698 /* top */ 5699 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5700 for (o = oebb; o < oebr; ++o) 5701 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5702 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5703 5704 /* Middle Slice */ 5705 for (j = 0; j < k - 1; ++j) { 5706 /* bottom */ 5707 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5708 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5709 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5710 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5711 /* middle */ 5712 for (i = 0; i < k - 1; ++i) { 5713 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5714 for (n = 0; n < k - 1; ++n) 5715 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5716 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5717 } 5718 /* top */ 5719 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5720 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5721 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5722 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5723 } 5724 5725 /* Top Slice */ 5726 /* bottom */ 5727 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5728 for (o = oetf; o < oetr; ++o) 5729 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5730 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5731 /* middle */ 5732 for (i = 0; i < k - 1; ++i) { 5733 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5734 for (n = 0; n < k - 1; ++n) 5735 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5736 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5737 } 5738 /* top */ 5739 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5740 for (o = oetl - 1; o >= oetb; --o) 5741 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5742 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5743 5744 foffset = offset; 5745 } 5746 break; 5747 default: 5748 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5749 } 5750 } 5751 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5752 /* Check permutation */ 5753 { 5754 PetscInt *check; 5755 5756 PetscCall(PetscMalloc1(size, &check)); 5757 for (i = 0; i < size; ++i) { 5758 check[i] = -1; 5759 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5760 } 5761 for (i = 0; i < size; ++i) check[perm[i]] = i; 5762 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5763 PetscCall(PetscFree(check)); 5764 } 5765 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5766 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5767 PetscInt *loc_perm; 5768 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5769 for (PetscInt i = 0; i < size; i++) { 5770 loc_perm[i] = perm[i]; 5771 loc_perm[size + i] = size + perm[i]; 5772 } 5773 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5774 } 5775 } 5776 PetscFunctionReturn(PETSC_SUCCESS); 5777 } 5778 5779 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5780 { 5781 PetscDS prob; 5782 PetscInt depth, Nf, h; 5783 DMLabel label; 5784 5785 PetscFunctionBeginHot; 5786 PetscCall(DMGetDS(dm, &prob)); 5787 Nf = prob->Nf; 5788 label = dm->depthLabel; 5789 *dspace = NULL; 5790 if (field < Nf) { 5791 PetscObject disc = prob->disc[field]; 5792 5793 if (disc->classid == PETSCFE_CLASSID) { 5794 PetscDualSpace dsp; 5795 5796 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5797 PetscCall(DMLabelGetNumValues(label, &depth)); 5798 PetscCall(DMLabelGetValue(label, point, &h)); 5799 h = depth - 1 - h; 5800 if (h) { 5801 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5802 } else { 5803 *dspace = dsp; 5804 } 5805 } 5806 } 5807 PetscFunctionReturn(PETSC_SUCCESS); 5808 } 5809 5810 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5811 { 5812 PetscScalar *array; 5813 const PetscScalar *vArray; 5814 const PetscInt *cone, *coneO; 5815 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5816 5817 PetscFunctionBeginHot; 5818 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5819 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5820 PetscCall(DMPlexGetCone(dm, point, &cone)); 5821 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5822 if (!values || !*values) { 5823 if ((point >= pStart) && (point < pEnd)) { 5824 PetscInt dof; 5825 5826 PetscCall(PetscSectionGetDof(section, point, &dof)); 5827 size += dof; 5828 } 5829 for (p = 0; p < numPoints; ++p) { 5830 const PetscInt cp = cone[p]; 5831 PetscInt dof; 5832 5833 if ((cp < pStart) || (cp >= pEnd)) continue; 5834 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5835 size += dof; 5836 } 5837 if (!values) { 5838 if (csize) *csize = size; 5839 PetscFunctionReturn(PETSC_SUCCESS); 5840 } 5841 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5842 } else { 5843 array = *values; 5844 } 5845 size = 0; 5846 PetscCall(VecGetArrayRead(v, &vArray)); 5847 if ((point >= pStart) && (point < pEnd)) { 5848 PetscInt dof, off, d; 5849 const PetscScalar *varr; 5850 5851 PetscCall(PetscSectionGetDof(section, point, &dof)); 5852 PetscCall(PetscSectionGetOffset(section, point, &off)); 5853 varr = &vArray[off]; 5854 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5855 size += dof; 5856 } 5857 for (p = 0; p < numPoints; ++p) { 5858 const PetscInt cp = cone[p]; 5859 PetscInt o = coneO[p]; 5860 PetscInt dof, off, d; 5861 const PetscScalar *varr; 5862 5863 if ((cp < pStart) || (cp >= pEnd)) continue; 5864 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5865 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5866 varr = &vArray[off]; 5867 if (o >= 0) { 5868 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5869 } else { 5870 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5871 } 5872 size += dof; 5873 } 5874 PetscCall(VecRestoreArrayRead(v, &vArray)); 5875 if (!*values) { 5876 if (csize) *csize = size; 5877 *values = array; 5878 } else { 5879 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5880 *csize = size; 5881 } 5882 PetscFunctionReturn(PETSC_SUCCESS); 5883 } 5884 5885 /* Compress out points not in the section */ 5886 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5887 { 5888 const PetscInt np = *numPoints; 5889 PetscInt pStart, pEnd, p, q; 5890 5891 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5892 for (p = 0, q = 0; p < np; ++p) { 5893 const PetscInt r = points[p * 2]; 5894 if ((r >= pStart) && (r < pEnd)) { 5895 points[q * 2] = r; 5896 points[q * 2 + 1] = points[p * 2 + 1]; 5897 ++q; 5898 } 5899 } 5900 *numPoints = q; 5901 return PETSC_SUCCESS; 5902 } 5903 5904 /* Compressed closure does not apply closure permutation */ 5905 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5906 { 5907 const PetscInt *cla = NULL; 5908 PetscInt np, *pts = NULL; 5909 5910 PetscFunctionBeginHot; 5911 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5912 if (!ornt && *clPoints) { 5913 PetscInt dof, off; 5914 5915 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5916 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5917 PetscCall(ISGetIndices(*clPoints, &cla)); 5918 np = dof / 2; 5919 pts = (PetscInt *)&cla[off]; 5920 } else { 5921 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 5922 PetscCall(CompressPoints_Private(section, &np, pts)); 5923 } 5924 *numPoints = np; 5925 *points = pts; 5926 *clp = cla; 5927 PetscFunctionReturn(PETSC_SUCCESS); 5928 } 5929 5930 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5931 { 5932 PetscFunctionBeginHot; 5933 if (!*clPoints) { 5934 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5935 } else { 5936 PetscCall(ISRestoreIndices(*clPoints, clp)); 5937 } 5938 *numPoints = 0; 5939 *points = NULL; 5940 *clSec = NULL; 5941 *clPoints = NULL; 5942 *clp = NULL; 5943 PetscFunctionReturn(PETSC_SUCCESS); 5944 } 5945 5946 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5947 { 5948 PetscInt offset = 0, p; 5949 const PetscInt **perms = NULL; 5950 const PetscScalar **flips = NULL; 5951 5952 PetscFunctionBeginHot; 5953 *size = 0; 5954 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5955 for (p = 0; p < numPoints; p++) { 5956 const PetscInt point = points[2 * p]; 5957 const PetscInt *perm = perms ? perms[p] : NULL; 5958 const PetscScalar *flip = flips ? flips[p] : NULL; 5959 PetscInt dof, off, d; 5960 const PetscScalar *varr; 5961 5962 PetscCall(PetscSectionGetDof(section, point, &dof)); 5963 PetscCall(PetscSectionGetOffset(section, point, &off)); 5964 varr = &vArray[off]; 5965 if (clperm) { 5966 if (perm) { 5967 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5968 } else { 5969 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5970 } 5971 if (flip) { 5972 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5973 } 5974 } else { 5975 if (perm) { 5976 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5977 } else { 5978 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5979 } 5980 if (flip) { 5981 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5982 } 5983 } 5984 offset += dof; 5985 } 5986 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5987 *size = offset; 5988 PetscFunctionReturn(PETSC_SUCCESS); 5989 } 5990 5991 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[]) 5992 { 5993 PetscInt offset = 0, f; 5994 5995 PetscFunctionBeginHot; 5996 *size = 0; 5997 for (f = 0; f < numFields; ++f) { 5998 PetscInt p; 5999 const PetscInt **perms = NULL; 6000 const PetscScalar **flips = NULL; 6001 6002 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6003 for (p = 0; p < numPoints; p++) { 6004 const PetscInt point = points[2 * p]; 6005 PetscInt fdof, foff, b; 6006 const PetscScalar *varr; 6007 const PetscInt *perm = perms ? perms[p] : NULL; 6008 const PetscScalar *flip = flips ? flips[p] : NULL; 6009 6010 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6011 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6012 varr = &vArray[foff]; 6013 if (clperm) { 6014 if (perm) { 6015 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6016 } else { 6017 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6018 } 6019 if (flip) { 6020 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6021 } 6022 } else { 6023 if (perm) { 6024 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6025 } else { 6026 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6027 } 6028 if (flip) { 6029 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6030 } 6031 } 6032 offset += fdof; 6033 } 6034 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6035 } 6036 *size = offset; 6037 PetscFunctionReturn(PETSC_SUCCESS); 6038 } 6039 6040 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6041 { 6042 PetscSection clSection; 6043 IS clPoints; 6044 PetscInt *points = NULL; 6045 const PetscInt *clp, *perm = NULL; 6046 PetscInt depth, numFields, numPoints, asize; 6047 6048 PetscFunctionBeginHot; 6049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6050 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6051 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6052 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6053 PetscCall(DMPlexGetDepth(dm, &depth)); 6054 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6055 if (depth == 1 && numFields < 2) { 6056 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6057 PetscFunctionReturn(PETSC_SUCCESS); 6058 } 6059 /* Get points */ 6060 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6061 /* Get sizes */ 6062 asize = 0; 6063 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6064 PetscInt dof; 6065 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6066 asize += dof; 6067 } 6068 if (values) { 6069 const PetscScalar *vArray; 6070 PetscInt size; 6071 6072 if (*values) { 6073 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); 6074 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6075 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6076 PetscCall(VecGetArrayRead(v, &vArray)); 6077 /* Get values */ 6078 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6079 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6080 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6081 /* Cleanup array */ 6082 PetscCall(VecRestoreArrayRead(v, &vArray)); 6083 } 6084 if (csize) *csize = asize; 6085 /* Cleanup points */ 6086 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6087 PetscFunctionReturn(PETSC_SUCCESS); 6088 } 6089 6090 /*@C 6091 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6092 6093 Not collective 6094 6095 Input Parameters: 6096 + dm - The `DM` 6097 . section - The section describing the layout in `v`, or `NULL` to use the default section 6098 . v - The local vector 6099 - point - The point in the `DM` 6100 6101 Input/Output Parameters: 6102 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6103 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6104 if the user provided `NULL`, it is a borrowed array and should not be freed 6105 6106 Level: intermediate 6107 6108 Notes: 6109 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6110 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6111 assembly function, and a user may already have allocated storage for this operation. 6112 6113 A typical use could be 6114 .vb 6115 values = NULL; 6116 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6117 for (cl = 0; cl < clSize; ++cl) { 6118 <Compute on closure> 6119 } 6120 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6121 .ve 6122 or 6123 .vb 6124 PetscMalloc1(clMaxSize, &values); 6125 for (p = pStart; p < pEnd; ++p) { 6126 clSize = clMaxSize; 6127 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6128 for (cl = 0; cl < clSize; ++cl) { 6129 <Compute on closure> 6130 } 6131 } 6132 PetscFree(values); 6133 .ve 6134 6135 Fortran Notes: 6136 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6137 6138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6139 @*/ 6140 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6141 { 6142 PetscFunctionBeginHot; 6143 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6144 PetscFunctionReturn(PETSC_SUCCESS); 6145 } 6146 6147 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6148 { 6149 DMLabel depthLabel; 6150 PetscSection clSection; 6151 IS clPoints; 6152 PetscScalar *array; 6153 const PetscScalar *vArray; 6154 PetscInt *points = NULL; 6155 const PetscInt *clp, *perm = NULL; 6156 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6157 6158 PetscFunctionBeginHot; 6159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6160 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6161 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6162 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6163 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6164 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6165 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6166 if (mdepth == 1 && numFields < 2) { 6167 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6168 PetscFunctionReturn(PETSC_SUCCESS); 6169 } 6170 /* Get points */ 6171 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6172 for (clsize = 0, p = 0; p < Np; p++) { 6173 PetscInt dof; 6174 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6175 clsize += dof; 6176 } 6177 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6178 /* Filter points */ 6179 for (p = 0; p < numPoints * 2; p += 2) { 6180 PetscInt dep; 6181 6182 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6183 if (dep != depth) continue; 6184 points[Np * 2 + 0] = points[p]; 6185 points[Np * 2 + 1] = points[p + 1]; 6186 ++Np; 6187 } 6188 /* Get array */ 6189 if (!values || !*values) { 6190 PetscInt asize = 0, dof; 6191 6192 for (p = 0; p < Np * 2; p += 2) { 6193 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6194 asize += dof; 6195 } 6196 if (!values) { 6197 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6198 if (csize) *csize = asize; 6199 PetscFunctionReturn(PETSC_SUCCESS); 6200 } 6201 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6202 } else { 6203 array = *values; 6204 } 6205 PetscCall(VecGetArrayRead(v, &vArray)); 6206 /* Get values */ 6207 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6208 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6209 /* Cleanup points */ 6210 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6211 /* Cleanup array */ 6212 PetscCall(VecRestoreArrayRead(v, &vArray)); 6213 if (!*values) { 6214 if (csize) *csize = size; 6215 *values = array; 6216 } else { 6217 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6218 *csize = size; 6219 } 6220 PetscFunctionReturn(PETSC_SUCCESS); 6221 } 6222 6223 /*@C 6224 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6225 6226 Not collective 6227 6228 Input Parameters: 6229 + dm - The `DM` 6230 . section - The section describing the layout in `v`, or `NULL` to use the default section 6231 . v - The local vector 6232 . point - The point in the `DM` 6233 . csize - The number of values in the closure, or `NULL` 6234 - values - The array of values, which is a borrowed array and should not be freed 6235 6236 Level: intermediate 6237 6238 Note: 6239 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6240 6241 Fortran Notes: 6242 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6243 6244 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6245 @*/ 6246 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6247 { 6248 PetscInt size = 0; 6249 6250 PetscFunctionBegin; 6251 /* Should work without recalculating size */ 6252 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6253 *values = NULL; 6254 PetscFunctionReturn(PETSC_SUCCESS); 6255 } 6256 6257 static inline void add(PetscScalar *x, PetscScalar y) 6258 { 6259 *x += y; 6260 } 6261 static inline void insert(PetscScalar *x, PetscScalar y) 6262 { 6263 *x = y; 6264 } 6265 6266 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[]) 6267 { 6268 PetscInt cdof; /* The number of constraints on this point */ 6269 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6270 PetscScalar *a; 6271 PetscInt off, cind = 0, k; 6272 6273 PetscFunctionBegin; 6274 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6275 PetscCall(PetscSectionGetOffset(section, point, &off)); 6276 a = &array[off]; 6277 if (!cdof || setBC) { 6278 if (clperm) { 6279 if (perm) { 6280 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6281 } else { 6282 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6283 } 6284 } else { 6285 if (perm) { 6286 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6287 } else { 6288 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6289 } 6290 } 6291 } else { 6292 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6293 if (clperm) { 6294 if (perm) { 6295 for (k = 0; k < dof; ++k) { 6296 if ((cind < cdof) && (k == cdofs[cind])) { 6297 ++cind; 6298 continue; 6299 } 6300 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6301 } 6302 } else { 6303 for (k = 0; k < dof; ++k) { 6304 if ((cind < cdof) && (k == cdofs[cind])) { 6305 ++cind; 6306 continue; 6307 } 6308 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6309 } 6310 } 6311 } else { 6312 if (perm) { 6313 for (k = 0; k < dof; ++k) { 6314 if ((cind < cdof) && (k == cdofs[cind])) { 6315 ++cind; 6316 continue; 6317 } 6318 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6319 } 6320 } else { 6321 for (k = 0; k < dof; ++k) { 6322 if ((cind < cdof) && (k == cdofs[cind])) { 6323 ++cind; 6324 continue; 6325 } 6326 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6327 } 6328 } 6329 } 6330 } 6331 PetscFunctionReturn(PETSC_SUCCESS); 6332 } 6333 6334 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[]) 6335 { 6336 PetscInt cdof; /* The number of constraints on this point */ 6337 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6338 PetscScalar *a; 6339 PetscInt off, cind = 0, k; 6340 6341 PetscFunctionBegin; 6342 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6343 PetscCall(PetscSectionGetOffset(section, point, &off)); 6344 a = &array[off]; 6345 if (cdof) { 6346 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6347 if (clperm) { 6348 if (perm) { 6349 for (k = 0; k < dof; ++k) { 6350 if ((cind < cdof) && (k == cdofs[cind])) { 6351 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6352 cind++; 6353 } 6354 } 6355 } else { 6356 for (k = 0; k < dof; ++k) { 6357 if ((cind < cdof) && (k == cdofs[cind])) { 6358 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6359 cind++; 6360 } 6361 } 6362 } 6363 } else { 6364 if (perm) { 6365 for (k = 0; k < dof; ++k) { 6366 if ((cind < cdof) && (k == cdofs[cind])) { 6367 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6368 cind++; 6369 } 6370 } 6371 } else { 6372 for (k = 0; k < dof; ++k) { 6373 if ((cind < cdof) && (k == cdofs[cind])) { 6374 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6375 cind++; 6376 } 6377 } 6378 } 6379 } 6380 } 6381 PetscFunctionReturn(PETSC_SUCCESS); 6382 } 6383 6384 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[]) 6385 { 6386 PetscScalar *a; 6387 PetscInt fdof, foff, fcdof, foffset = *offset; 6388 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6389 PetscInt cind = 0, b; 6390 6391 PetscFunctionBegin; 6392 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6393 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6394 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6395 a = &array[foff]; 6396 if (!fcdof || setBC) { 6397 if (clperm) { 6398 if (perm) { 6399 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6400 } else { 6401 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6402 } 6403 } else { 6404 if (perm) { 6405 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6406 } else { 6407 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6408 } 6409 } 6410 } else { 6411 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6412 if (clperm) { 6413 if (perm) { 6414 for (b = 0; b < fdof; b++) { 6415 if ((cind < fcdof) && (b == fcdofs[cind])) { 6416 ++cind; 6417 continue; 6418 } 6419 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6420 } 6421 } else { 6422 for (b = 0; b < fdof; b++) { 6423 if ((cind < fcdof) && (b == fcdofs[cind])) { 6424 ++cind; 6425 continue; 6426 } 6427 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6428 } 6429 } 6430 } else { 6431 if (perm) { 6432 for (b = 0; b < fdof; b++) { 6433 if ((cind < fcdof) && (b == fcdofs[cind])) { 6434 ++cind; 6435 continue; 6436 } 6437 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6438 } 6439 } else { 6440 for (b = 0; b < fdof; b++) { 6441 if ((cind < fcdof) && (b == fcdofs[cind])) { 6442 ++cind; 6443 continue; 6444 } 6445 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6446 } 6447 } 6448 } 6449 } 6450 *offset += fdof; 6451 PetscFunctionReturn(PETSC_SUCCESS); 6452 } 6453 6454 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[]) 6455 { 6456 PetscScalar *a; 6457 PetscInt fdof, foff, fcdof, foffset = *offset; 6458 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6459 PetscInt Nc, cind = 0, ncind = 0, b; 6460 PetscBool ncSet, fcSet; 6461 6462 PetscFunctionBegin; 6463 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6464 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6465 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6466 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6467 a = &array[foff]; 6468 if (fcdof) { 6469 /* We just override fcdof and fcdofs with Ncc and comps */ 6470 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6471 if (clperm) { 6472 if (perm) { 6473 if (comps) { 6474 for (b = 0; b < fdof; b++) { 6475 ncSet = fcSet = PETSC_FALSE; 6476 if (b % Nc == comps[ncind]) { 6477 ncind = (ncind + 1) % Ncc; 6478 ncSet = PETSC_TRUE; 6479 } 6480 if ((cind < fcdof) && (b == fcdofs[cind])) { 6481 ++cind; 6482 fcSet = PETSC_TRUE; 6483 } 6484 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6485 } 6486 } else { 6487 for (b = 0; b < fdof; b++) { 6488 if ((cind < fcdof) && (b == fcdofs[cind])) { 6489 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6490 ++cind; 6491 } 6492 } 6493 } 6494 } else { 6495 if (comps) { 6496 for (b = 0; b < fdof; b++) { 6497 ncSet = fcSet = PETSC_FALSE; 6498 if (b % Nc == comps[ncind]) { 6499 ncind = (ncind + 1) % Ncc; 6500 ncSet = PETSC_TRUE; 6501 } 6502 if ((cind < fcdof) && (b == fcdofs[cind])) { 6503 ++cind; 6504 fcSet = PETSC_TRUE; 6505 } 6506 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6507 } 6508 } else { 6509 for (b = 0; b < fdof; b++) { 6510 if ((cind < fcdof) && (b == fcdofs[cind])) { 6511 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6512 ++cind; 6513 } 6514 } 6515 } 6516 } 6517 } else { 6518 if (perm) { 6519 if (comps) { 6520 for (b = 0; b < fdof; b++) { 6521 ncSet = fcSet = PETSC_FALSE; 6522 if (b % Nc == comps[ncind]) { 6523 ncind = (ncind + 1) % Ncc; 6524 ncSet = PETSC_TRUE; 6525 } 6526 if ((cind < fcdof) && (b == fcdofs[cind])) { 6527 ++cind; 6528 fcSet = PETSC_TRUE; 6529 } 6530 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6531 } 6532 } else { 6533 for (b = 0; b < fdof; b++) { 6534 if ((cind < fcdof) && (b == fcdofs[cind])) { 6535 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6536 ++cind; 6537 } 6538 } 6539 } 6540 } else { 6541 if (comps) { 6542 for (b = 0; b < fdof; b++) { 6543 ncSet = fcSet = PETSC_FALSE; 6544 if (b % Nc == comps[ncind]) { 6545 ncind = (ncind + 1) % Ncc; 6546 ncSet = PETSC_TRUE; 6547 } 6548 if ((cind < fcdof) && (b == fcdofs[cind])) { 6549 ++cind; 6550 fcSet = PETSC_TRUE; 6551 } 6552 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6553 } 6554 } else { 6555 for (b = 0; b < fdof; b++) { 6556 if ((cind < fcdof) && (b == fcdofs[cind])) { 6557 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6558 ++cind; 6559 } 6560 } 6561 } 6562 } 6563 } 6564 } 6565 *offset += fdof; 6566 PetscFunctionReturn(PETSC_SUCCESS); 6567 } 6568 6569 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6570 { 6571 PetscScalar *array; 6572 const PetscInt *cone, *coneO; 6573 PetscInt pStart, pEnd, p, numPoints, off, dof; 6574 6575 PetscFunctionBeginHot; 6576 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6577 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6578 PetscCall(DMPlexGetCone(dm, point, &cone)); 6579 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6580 PetscCall(VecGetArray(v, &array)); 6581 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6582 const PetscInt cp = !p ? point : cone[p - 1]; 6583 const PetscInt o = !p ? 0 : coneO[p - 1]; 6584 6585 if ((cp < pStart) || (cp >= pEnd)) { 6586 dof = 0; 6587 continue; 6588 } 6589 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6590 /* ADD_VALUES */ 6591 { 6592 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6593 PetscScalar *a; 6594 PetscInt cdof, coff, cind = 0, k; 6595 6596 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6597 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6598 a = &array[coff]; 6599 if (!cdof) { 6600 if (o >= 0) { 6601 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6602 } else { 6603 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6604 } 6605 } else { 6606 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6607 if (o >= 0) { 6608 for (k = 0; k < dof; ++k) { 6609 if ((cind < cdof) && (k == cdofs[cind])) { 6610 ++cind; 6611 continue; 6612 } 6613 a[k] += values[off + k]; 6614 } 6615 } else { 6616 for (k = 0; k < dof; ++k) { 6617 if ((cind < cdof) && (k == cdofs[cind])) { 6618 ++cind; 6619 continue; 6620 } 6621 a[k] += values[off + dof - k - 1]; 6622 } 6623 } 6624 } 6625 } 6626 } 6627 PetscCall(VecRestoreArray(v, &array)); 6628 PetscFunctionReturn(PETSC_SUCCESS); 6629 } 6630 6631 /*@C 6632 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6633 6634 Not collective 6635 6636 Input Parameters: 6637 + dm - The `DM` 6638 . section - The section describing the layout in `v`, or `NULL` to use the default section 6639 . v - The local vector 6640 . point - The point in the `DM` 6641 . values - The array of values 6642 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6643 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6644 6645 Level: intermediate 6646 6647 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6648 @*/ 6649 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6650 { 6651 PetscSection clSection; 6652 IS clPoints; 6653 PetscScalar *array; 6654 PetscInt *points = NULL; 6655 const PetscInt *clp, *clperm = NULL; 6656 PetscInt depth, numFields, numPoints, p, clsize; 6657 6658 PetscFunctionBeginHot; 6659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6660 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6661 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6662 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6663 PetscCall(DMPlexGetDepth(dm, &depth)); 6664 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6665 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6666 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6667 PetscFunctionReturn(PETSC_SUCCESS); 6668 } 6669 /* Get points */ 6670 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6671 for (clsize = 0, p = 0; p < numPoints; p++) { 6672 PetscInt dof; 6673 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6674 clsize += dof; 6675 } 6676 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6677 /* Get array */ 6678 PetscCall(VecGetArray(v, &array)); 6679 /* Get values */ 6680 if (numFields > 0) { 6681 PetscInt offset = 0, f; 6682 for (f = 0; f < numFields; ++f) { 6683 const PetscInt **perms = NULL; 6684 const PetscScalar **flips = NULL; 6685 6686 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6687 switch (mode) { 6688 case INSERT_VALUES: 6689 for (p = 0; p < numPoints; p++) { 6690 const PetscInt point = points[2 * p]; 6691 const PetscInt *perm = perms ? perms[p] : NULL; 6692 const PetscScalar *flip = flips ? flips[p] : NULL; 6693 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6694 } 6695 break; 6696 case INSERT_ALL_VALUES: 6697 for (p = 0; p < numPoints; p++) { 6698 const PetscInt point = points[2 * p]; 6699 const PetscInt *perm = perms ? perms[p] : NULL; 6700 const PetscScalar *flip = flips ? flips[p] : NULL; 6701 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6702 } 6703 break; 6704 case INSERT_BC_VALUES: 6705 for (p = 0; p < numPoints; p++) { 6706 const PetscInt point = points[2 * p]; 6707 const PetscInt *perm = perms ? perms[p] : NULL; 6708 const PetscScalar *flip = flips ? flips[p] : NULL; 6709 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6710 } 6711 break; 6712 case ADD_VALUES: 6713 for (p = 0; p < numPoints; p++) { 6714 const PetscInt point = points[2 * p]; 6715 const PetscInt *perm = perms ? perms[p] : NULL; 6716 const PetscScalar *flip = flips ? flips[p] : NULL; 6717 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6718 } 6719 break; 6720 case ADD_ALL_VALUES: 6721 for (p = 0; p < numPoints; p++) { 6722 const PetscInt point = points[2 * p]; 6723 const PetscInt *perm = perms ? perms[p] : NULL; 6724 const PetscScalar *flip = flips ? flips[p] : NULL; 6725 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6726 } 6727 break; 6728 case ADD_BC_VALUES: 6729 for (p = 0; p < numPoints; p++) { 6730 const PetscInt point = points[2 * p]; 6731 const PetscInt *perm = perms ? perms[p] : NULL; 6732 const PetscScalar *flip = flips ? flips[p] : NULL; 6733 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6734 } 6735 break; 6736 default: 6737 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6738 } 6739 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6740 } 6741 } else { 6742 PetscInt dof, off; 6743 const PetscInt **perms = NULL; 6744 const PetscScalar **flips = NULL; 6745 6746 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6747 switch (mode) { 6748 case INSERT_VALUES: 6749 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6750 const PetscInt point = points[2 * p]; 6751 const PetscInt *perm = perms ? perms[p] : NULL; 6752 const PetscScalar *flip = flips ? flips[p] : NULL; 6753 PetscCall(PetscSectionGetDof(section, point, &dof)); 6754 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6755 } 6756 break; 6757 case INSERT_ALL_VALUES: 6758 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6759 const PetscInt point = points[2 * p]; 6760 const PetscInt *perm = perms ? perms[p] : NULL; 6761 const PetscScalar *flip = flips ? flips[p] : NULL; 6762 PetscCall(PetscSectionGetDof(section, point, &dof)); 6763 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6764 } 6765 break; 6766 case INSERT_BC_VALUES: 6767 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6768 const PetscInt point = points[2 * p]; 6769 const PetscInt *perm = perms ? perms[p] : NULL; 6770 const PetscScalar *flip = flips ? flips[p] : NULL; 6771 PetscCall(PetscSectionGetDof(section, point, &dof)); 6772 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6773 } 6774 break; 6775 case ADD_VALUES: 6776 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6777 const PetscInt point = points[2 * p]; 6778 const PetscInt *perm = perms ? perms[p] : NULL; 6779 const PetscScalar *flip = flips ? flips[p] : NULL; 6780 PetscCall(PetscSectionGetDof(section, point, &dof)); 6781 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6782 } 6783 break; 6784 case ADD_ALL_VALUES: 6785 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6786 const PetscInt point = points[2 * p]; 6787 const PetscInt *perm = perms ? perms[p] : NULL; 6788 const PetscScalar *flip = flips ? flips[p] : NULL; 6789 PetscCall(PetscSectionGetDof(section, point, &dof)); 6790 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6791 } 6792 break; 6793 case ADD_BC_VALUES: 6794 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6795 const PetscInt point = points[2 * p]; 6796 const PetscInt *perm = perms ? perms[p] : NULL; 6797 const PetscScalar *flip = flips ? flips[p] : NULL; 6798 PetscCall(PetscSectionGetDof(section, point, &dof)); 6799 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6800 } 6801 break; 6802 default: 6803 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6804 } 6805 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6806 } 6807 /* Cleanup points */ 6808 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6809 /* Cleanup array */ 6810 PetscCall(VecRestoreArray(v, &array)); 6811 PetscFunctionReturn(PETSC_SUCCESS); 6812 } 6813 6814 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6815 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6816 { 6817 PetscFunctionBegin; 6818 *contains = PETSC_TRUE; 6819 if (label) { 6820 PetscInt fdof; 6821 6822 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6823 if (!*contains) { 6824 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6825 *offset += fdof; 6826 PetscFunctionReturn(PETSC_SUCCESS); 6827 } 6828 } 6829 PetscFunctionReturn(PETSC_SUCCESS); 6830 } 6831 6832 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6833 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) 6834 { 6835 PetscSection clSection; 6836 IS clPoints; 6837 PetscScalar *array; 6838 PetscInt *points = NULL; 6839 const PetscInt *clp; 6840 PetscInt numFields, numPoints, p; 6841 PetscInt offset = 0, f; 6842 6843 PetscFunctionBeginHot; 6844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6845 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6846 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6847 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6848 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6849 /* Get points */ 6850 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6851 /* Get array */ 6852 PetscCall(VecGetArray(v, &array)); 6853 /* Get values */ 6854 for (f = 0; f < numFields; ++f) { 6855 const PetscInt **perms = NULL; 6856 const PetscScalar **flips = NULL; 6857 PetscBool contains; 6858 6859 if (!fieldActive[f]) { 6860 for (p = 0; p < numPoints * 2; p += 2) { 6861 PetscInt fdof; 6862 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6863 offset += fdof; 6864 } 6865 continue; 6866 } 6867 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6868 switch (mode) { 6869 case INSERT_VALUES: 6870 for (p = 0; p < numPoints; p++) { 6871 const PetscInt point = points[2 * p]; 6872 const PetscInt *perm = perms ? perms[p] : NULL; 6873 const PetscScalar *flip = flips ? flips[p] : NULL; 6874 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6875 if (!contains) continue; 6876 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6877 } 6878 break; 6879 case INSERT_ALL_VALUES: 6880 for (p = 0; p < numPoints; p++) { 6881 const PetscInt point = points[2 * p]; 6882 const PetscInt *perm = perms ? perms[p] : NULL; 6883 const PetscScalar *flip = flips ? flips[p] : NULL; 6884 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6885 if (!contains) continue; 6886 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6887 } 6888 break; 6889 case INSERT_BC_VALUES: 6890 for (p = 0; p < numPoints; p++) { 6891 const PetscInt point = points[2 * p]; 6892 const PetscInt *perm = perms ? perms[p] : NULL; 6893 const PetscScalar *flip = flips ? flips[p] : NULL; 6894 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6895 if (!contains) continue; 6896 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6897 } 6898 break; 6899 case ADD_VALUES: 6900 for (p = 0; p < numPoints; p++) { 6901 const PetscInt point = points[2 * p]; 6902 const PetscInt *perm = perms ? perms[p] : NULL; 6903 const PetscScalar *flip = flips ? flips[p] : NULL; 6904 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6905 if (!contains) continue; 6906 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6907 } 6908 break; 6909 case ADD_ALL_VALUES: 6910 for (p = 0; p < numPoints; p++) { 6911 const PetscInt point = points[2 * p]; 6912 const PetscInt *perm = perms ? perms[p] : NULL; 6913 const PetscScalar *flip = flips ? flips[p] : NULL; 6914 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6915 if (!contains) continue; 6916 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6917 } 6918 break; 6919 default: 6920 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6921 } 6922 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6923 } 6924 /* Cleanup points */ 6925 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6926 /* Cleanup array */ 6927 PetscCall(VecRestoreArray(v, &array)); 6928 PetscFunctionReturn(PETSC_SUCCESS); 6929 } 6930 6931 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6932 { 6933 PetscMPIInt rank; 6934 PetscInt i, j; 6935 6936 PetscFunctionBegin; 6937 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6938 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6939 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6940 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6941 numCIndices = numCIndices ? numCIndices : numRIndices; 6942 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 6943 for (i = 0; i < numRIndices; i++) { 6944 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6945 for (j = 0; j < numCIndices; j++) { 6946 #if defined(PETSC_USE_COMPLEX) 6947 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6948 #else 6949 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6950 #endif 6951 } 6952 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6953 } 6954 PetscFunctionReturn(PETSC_SUCCESS); 6955 } 6956 6957 /* 6958 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6959 6960 Input Parameters: 6961 + section - The section for this data layout 6962 . islocal - Is the section (and thus indices being requested) local or global? 6963 . point - The point contributing dofs with these indices 6964 . off - The global offset of this point 6965 . loff - The local offset of each field 6966 . setBC - The flag determining whether to include indices of boundary values 6967 . perm - A permutation of the dofs on this point, or NULL 6968 - indperm - A permutation of the entire indices array, or NULL 6969 6970 Output Parameter: 6971 . indices - Indices for dofs on this point 6972 6973 Level: developer 6974 6975 Note: The indices could be local or global, depending on the value of 'off'. 6976 */ 6977 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6978 { 6979 PetscInt dof; /* The number of unknowns on this point */ 6980 PetscInt cdof; /* The number of constraints on this point */ 6981 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6982 PetscInt cind = 0, k; 6983 6984 PetscFunctionBegin; 6985 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6986 PetscCall(PetscSectionGetDof(section, point, &dof)); 6987 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6988 if (!cdof || setBC) { 6989 for (k = 0; k < dof; ++k) { 6990 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6991 const PetscInt ind = indperm ? indperm[preind] : preind; 6992 6993 indices[ind] = off + k; 6994 } 6995 } else { 6996 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6997 for (k = 0; k < dof; ++k) { 6998 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6999 const PetscInt ind = indperm ? indperm[preind] : preind; 7000 7001 if ((cind < cdof) && (k == cdofs[cind])) { 7002 /* Insert check for returning constrained indices */ 7003 indices[ind] = -(off + k + 1); 7004 ++cind; 7005 } else { 7006 indices[ind] = off + k - (islocal ? 0 : cind); 7007 } 7008 } 7009 } 7010 *loff += dof; 7011 PetscFunctionReturn(PETSC_SUCCESS); 7012 } 7013 7014 /* 7015 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7016 7017 Input Parameters: 7018 + section - a section (global or local) 7019 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7020 . point - point within section 7021 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7022 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7023 . setBC - identify constrained (boundary condition) points via involution. 7024 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7025 . permsoff - offset 7026 - indperm - index permutation 7027 7028 Output Parameter: 7029 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7030 . indices - array to hold indices (as defined by section) of each dof associated with point 7031 7032 Notes: 7033 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7034 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7035 in the local vector. 7036 7037 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7038 significant). It is invalid to call with a global section and setBC=true. 7039 7040 Developer Note: 7041 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7042 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7043 offset could be obtained from the section instead of passing it explicitly as we do now. 7044 7045 Example: 7046 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7047 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7048 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7049 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. 7050 7051 Level: developer 7052 */ 7053 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[]) 7054 { 7055 PetscInt numFields, foff, f; 7056 7057 PetscFunctionBegin; 7058 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7059 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7060 for (f = 0, foff = 0; f < numFields; ++f) { 7061 PetscInt fdof, cfdof; 7062 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7063 PetscInt cind = 0, b; 7064 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7065 7066 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7067 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7068 if (!cfdof || setBC) { 7069 for (b = 0; b < fdof; ++b) { 7070 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7071 const PetscInt ind = indperm ? indperm[preind] : preind; 7072 7073 indices[ind] = off + foff + b; 7074 } 7075 } else { 7076 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7077 for (b = 0; b < fdof; ++b) { 7078 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7079 const PetscInt ind = indperm ? indperm[preind] : preind; 7080 7081 if ((cind < cfdof) && (b == fcdofs[cind])) { 7082 indices[ind] = -(off + foff + b + 1); 7083 ++cind; 7084 } else { 7085 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7086 } 7087 } 7088 } 7089 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7090 foffs[f] += fdof; 7091 } 7092 PetscFunctionReturn(PETSC_SUCCESS); 7093 } 7094 7095 /* 7096 This version believes the globalSection offsets for each field, rather than just the point offset 7097 7098 . foffs - The offset into 'indices' for each field, since it is segregated by field 7099 7100 Notes: 7101 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7102 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7103 */ 7104 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7105 { 7106 PetscInt numFields, foff, f; 7107 7108 PetscFunctionBegin; 7109 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7110 for (f = 0; f < numFields; ++f) { 7111 PetscInt fdof, cfdof; 7112 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7113 PetscInt cind = 0, b; 7114 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7115 7116 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7117 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7118 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7119 if (!cfdof) { 7120 for (b = 0; b < fdof; ++b) { 7121 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7122 const PetscInt ind = indperm ? indperm[preind] : preind; 7123 7124 indices[ind] = foff + b; 7125 } 7126 } else { 7127 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7128 for (b = 0; b < fdof; ++b) { 7129 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7130 const PetscInt ind = indperm ? indperm[preind] : preind; 7131 7132 if ((cind < cfdof) && (b == fcdofs[cind])) { 7133 indices[ind] = -(foff + b + 1); 7134 ++cind; 7135 } else { 7136 indices[ind] = foff + b - cind; 7137 } 7138 } 7139 } 7140 foffs[f] += fdof; 7141 } 7142 PetscFunctionReturn(PETSC_SUCCESS); 7143 } 7144 7145 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) 7146 { 7147 Mat cMat; 7148 PetscSection aSec, cSec; 7149 IS aIS; 7150 PetscInt aStart = -1, aEnd = -1; 7151 const PetscInt *anchors; 7152 PetscInt numFields, f, p, q, newP = 0; 7153 PetscInt newNumPoints = 0, newNumIndices = 0; 7154 PetscInt *newPoints, *indices, *newIndices; 7155 PetscInt maxAnchor, maxDof; 7156 PetscInt newOffsets[32]; 7157 PetscInt *pointMatOffsets[32]; 7158 PetscInt *newPointOffsets[32]; 7159 PetscScalar *pointMat[32]; 7160 PetscScalar *newValues = NULL, *tmpValues; 7161 PetscBool anyConstrained = PETSC_FALSE; 7162 7163 PetscFunctionBegin; 7164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7165 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7166 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7167 7168 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7169 /* if there are point-to-point constraints */ 7170 if (aSec) { 7171 PetscCall(PetscArrayzero(newOffsets, 32)); 7172 PetscCall(ISGetIndices(aIS, &anchors)); 7173 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7174 /* figure out how many points are going to be in the new element matrix 7175 * (we allow double counting, because it's all just going to be summed 7176 * into the global matrix anyway) */ 7177 for (p = 0; p < 2 * numPoints; p += 2) { 7178 PetscInt b = points[p]; 7179 PetscInt bDof = 0, bSecDof; 7180 7181 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7182 if (!bSecDof) continue; 7183 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7184 if (bDof) { 7185 /* this point is constrained */ 7186 /* it is going to be replaced by its anchors */ 7187 PetscInt bOff, q; 7188 7189 anyConstrained = PETSC_TRUE; 7190 newNumPoints += bDof; 7191 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7192 for (q = 0; q < bDof; q++) { 7193 PetscInt a = anchors[bOff + q]; 7194 PetscInt aDof; 7195 7196 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7197 newNumIndices += aDof; 7198 for (f = 0; f < numFields; ++f) { 7199 PetscInt fDof; 7200 7201 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7202 newOffsets[f + 1] += fDof; 7203 } 7204 } 7205 } else { 7206 /* this point is not constrained */ 7207 newNumPoints++; 7208 newNumIndices += bSecDof; 7209 for (f = 0; f < numFields; ++f) { 7210 PetscInt fDof; 7211 7212 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7213 newOffsets[f + 1] += fDof; 7214 } 7215 } 7216 } 7217 } 7218 if (!anyConstrained) { 7219 if (outNumPoints) *outNumPoints = 0; 7220 if (outNumIndices) *outNumIndices = 0; 7221 if (outPoints) *outPoints = NULL; 7222 if (outValues) *outValues = NULL; 7223 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7224 PetscFunctionReturn(PETSC_SUCCESS); 7225 } 7226 7227 if (outNumPoints) *outNumPoints = newNumPoints; 7228 if (outNumIndices) *outNumIndices = newNumIndices; 7229 7230 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7231 7232 if (!outPoints && !outValues) { 7233 if (offsets) { 7234 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7235 } 7236 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7237 PetscFunctionReturn(PETSC_SUCCESS); 7238 } 7239 7240 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7241 7242 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7243 7244 /* workspaces */ 7245 if (numFields) { 7246 for (f = 0; f < numFields; f++) { 7247 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7248 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7249 } 7250 } else { 7251 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7252 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7253 } 7254 7255 /* get workspaces for the point-to-point matrices */ 7256 if (numFields) { 7257 PetscInt totalOffset, totalMatOffset; 7258 7259 for (p = 0; p < numPoints; p++) { 7260 PetscInt b = points[2 * p]; 7261 PetscInt bDof = 0, bSecDof; 7262 7263 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7264 if (!bSecDof) { 7265 for (f = 0; f < numFields; f++) { 7266 newPointOffsets[f][p + 1] = 0; 7267 pointMatOffsets[f][p + 1] = 0; 7268 } 7269 continue; 7270 } 7271 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7272 if (bDof) { 7273 for (f = 0; f < numFields; f++) { 7274 PetscInt fDof, q, bOff, allFDof = 0; 7275 7276 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7277 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7278 for (q = 0; q < bDof; q++) { 7279 PetscInt a = anchors[bOff + q]; 7280 PetscInt aFDof; 7281 7282 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7283 allFDof += aFDof; 7284 } 7285 newPointOffsets[f][p + 1] = allFDof; 7286 pointMatOffsets[f][p + 1] = fDof * allFDof; 7287 } 7288 } else { 7289 for (f = 0; f < numFields; f++) { 7290 PetscInt fDof; 7291 7292 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7293 newPointOffsets[f][p + 1] = fDof; 7294 pointMatOffsets[f][p + 1] = 0; 7295 } 7296 } 7297 } 7298 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7299 newPointOffsets[f][0] = totalOffset; 7300 pointMatOffsets[f][0] = totalMatOffset; 7301 for (p = 0; p < numPoints; p++) { 7302 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7303 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7304 } 7305 totalOffset = newPointOffsets[f][numPoints]; 7306 totalMatOffset = pointMatOffsets[f][numPoints]; 7307 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7308 } 7309 } else { 7310 for (p = 0; p < numPoints; p++) { 7311 PetscInt b = points[2 * p]; 7312 PetscInt bDof = 0, bSecDof; 7313 7314 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7315 if (!bSecDof) { 7316 newPointOffsets[0][p + 1] = 0; 7317 pointMatOffsets[0][p + 1] = 0; 7318 continue; 7319 } 7320 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7321 if (bDof) { 7322 PetscInt bOff, q, allDof = 0; 7323 7324 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7325 for (q = 0; q < bDof; q++) { 7326 PetscInt a = anchors[bOff + q], aDof; 7327 7328 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7329 allDof += aDof; 7330 } 7331 newPointOffsets[0][p + 1] = allDof; 7332 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7333 } else { 7334 newPointOffsets[0][p + 1] = bSecDof; 7335 pointMatOffsets[0][p + 1] = 0; 7336 } 7337 } 7338 newPointOffsets[0][0] = 0; 7339 pointMatOffsets[0][0] = 0; 7340 for (p = 0; p < numPoints; p++) { 7341 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7342 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7343 } 7344 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7345 } 7346 7347 /* output arrays */ 7348 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7349 7350 /* get the point-to-point matrices; construct newPoints */ 7351 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7352 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7353 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7354 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7355 if (numFields) { 7356 for (p = 0, newP = 0; p < numPoints; p++) { 7357 PetscInt b = points[2 * p]; 7358 PetscInt o = points[2 * p + 1]; 7359 PetscInt bDof = 0, bSecDof; 7360 7361 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7362 if (!bSecDof) continue; 7363 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7364 if (bDof) { 7365 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7366 7367 fStart[0] = 0; 7368 fEnd[0] = 0; 7369 for (f = 0; f < numFields; f++) { 7370 PetscInt fDof; 7371 7372 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7373 fStart[f + 1] = fStart[f] + fDof; 7374 fEnd[f + 1] = fStart[f + 1]; 7375 } 7376 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7377 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7378 7379 fAnchorStart[0] = 0; 7380 fAnchorEnd[0] = 0; 7381 for (f = 0; f < numFields; f++) { 7382 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7383 7384 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7385 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7386 } 7387 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7388 for (q = 0; q < bDof; q++) { 7389 PetscInt a = anchors[bOff + q], aOff; 7390 7391 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7392 newPoints[2 * (newP + q)] = a; 7393 newPoints[2 * (newP + q) + 1] = 0; 7394 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7395 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7396 } 7397 newP += bDof; 7398 7399 if (outValues) { 7400 /* get the point-to-point submatrix */ 7401 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])); 7402 } 7403 } else { 7404 newPoints[2 * newP] = b; 7405 newPoints[2 * newP + 1] = o; 7406 newP++; 7407 } 7408 } 7409 } else { 7410 for (p = 0; p < numPoints; p++) { 7411 PetscInt b = points[2 * p]; 7412 PetscInt o = points[2 * p + 1]; 7413 PetscInt bDof = 0, bSecDof; 7414 7415 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7416 if (!bSecDof) continue; 7417 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7418 if (bDof) { 7419 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7420 7421 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7422 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7423 7424 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7425 for (q = 0; q < bDof; q++) { 7426 PetscInt a = anchors[bOff + q], aOff; 7427 7428 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7429 7430 newPoints[2 * (newP + q)] = a; 7431 newPoints[2 * (newP + q) + 1] = 0; 7432 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7433 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7434 } 7435 newP += bDof; 7436 7437 /* get the point-to-point submatrix */ 7438 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7439 } else { 7440 newPoints[2 * newP] = b; 7441 newPoints[2 * newP + 1] = o; 7442 newP++; 7443 } 7444 } 7445 } 7446 7447 if (outValues) { 7448 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7449 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7450 /* multiply constraints on the right */ 7451 if (numFields) { 7452 for (f = 0; f < numFields; f++) { 7453 PetscInt oldOff = offsets[f]; 7454 7455 for (p = 0; p < numPoints; p++) { 7456 PetscInt cStart = newPointOffsets[f][p]; 7457 PetscInt b = points[2 * p]; 7458 PetscInt c, r, k; 7459 PetscInt dof; 7460 7461 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7462 if (!dof) continue; 7463 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7464 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7465 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7466 7467 for (r = 0; r < numIndices; r++) { 7468 for (c = 0; c < nCols; c++) { 7469 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7470 } 7471 } 7472 } else { 7473 /* copy this column as is */ 7474 for (r = 0; r < numIndices; r++) { 7475 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7476 } 7477 } 7478 oldOff += dof; 7479 } 7480 } 7481 } else { 7482 PetscInt oldOff = 0; 7483 for (p = 0; p < numPoints; p++) { 7484 PetscInt cStart = newPointOffsets[0][p]; 7485 PetscInt b = points[2 * p]; 7486 PetscInt c, r, k; 7487 PetscInt dof; 7488 7489 PetscCall(PetscSectionGetDof(section, b, &dof)); 7490 if (!dof) continue; 7491 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7492 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7493 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7494 7495 for (r = 0; r < numIndices; r++) { 7496 for (c = 0; c < nCols; c++) { 7497 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7498 } 7499 } 7500 } else { 7501 /* copy this column as is */ 7502 for (r = 0; r < numIndices; r++) { 7503 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7504 } 7505 } 7506 oldOff += dof; 7507 } 7508 } 7509 7510 if (multiplyLeft) { 7511 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7512 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7513 /* multiply constraints transpose on the left */ 7514 if (numFields) { 7515 for (f = 0; f < numFields; f++) { 7516 PetscInt oldOff = offsets[f]; 7517 7518 for (p = 0; p < numPoints; p++) { 7519 PetscInt rStart = newPointOffsets[f][p]; 7520 PetscInt b = points[2 * p]; 7521 PetscInt c, r, k; 7522 PetscInt dof; 7523 7524 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7525 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7526 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7527 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7528 7529 for (r = 0; r < nRows; r++) { 7530 for (c = 0; c < newNumIndices; c++) { 7531 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7532 } 7533 } 7534 } else { 7535 /* copy this row as is */ 7536 for (r = 0; r < dof; r++) { 7537 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7538 } 7539 } 7540 oldOff += dof; 7541 } 7542 } 7543 } else { 7544 PetscInt oldOff = 0; 7545 7546 for (p = 0; p < numPoints; p++) { 7547 PetscInt rStart = newPointOffsets[0][p]; 7548 PetscInt b = points[2 * p]; 7549 PetscInt c, r, k; 7550 PetscInt dof; 7551 7552 PetscCall(PetscSectionGetDof(section, b, &dof)); 7553 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7554 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7555 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7556 7557 for (r = 0; r < nRows; r++) { 7558 for (c = 0; c < newNumIndices; c++) { 7559 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7560 } 7561 } 7562 } else { 7563 /* copy this row as is */ 7564 for (r = 0; r < dof; r++) { 7565 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7566 } 7567 } 7568 oldOff += dof; 7569 } 7570 } 7571 7572 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7573 } else { 7574 newValues = tmpValues; 7575 } 7576 } 7577 7578 /* clean up */ 7579 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7580 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7581 7582 if (numFields) { 7583 for (f = 0; f < numFields; f++) { 7584 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7585 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7586 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7587 } 7588 } else { 7589 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7590 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7591 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7592 } 7593 PetscCall(ISRestoreIndices(aIS, &anchors)); 7594 7595 /* output */ 7596 if (outPoints) { 7597 *outPoints = newPoints; 7598 } else { 7599 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7600 } 7601 if (outValues) *outValues = newValues; 7602 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7603 PetscFunctionReturn(PETSC_SUCCESS); 7604 } 7605 7606 /*@C 7607 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7608 7609 Not collective 7610 7611 Input Parameters: 7612 + dm - The `DM` 7613 . section - The `PetscSection` describing the points (a local section) 7614 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7615 . point - The point defining the closure 7616 - useClPerm - Use the closure point permutation if available 7617 7618 Output Parameters: 7619 + numIndices - The number of dof indices in the closure of point with the input sections 7620 . indices - The dof indices 7621 . outOffsets - Array to write the field offsets into, or `NULL` 7622 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7623 7624 Level: advanced 7625 7626 Notes: 7627 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7628 7629 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7630 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7631 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7632 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7633 indices (with the above semantics) are implied. 7634 7635 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7636 `PetscSection`, `DMGetGlobalSection()` 7637 @*/ 7638 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7639 { 7640 /* Closure ordering */ 7641 PetscSection clSection; 7642 IS clPoints; 7643 const PetscInt *clp; 7644 PetscInt *points; 7645 const PetscInt *clperm = NULL; 7646 /* Dof permutation and sign flips */ 7647 const PetscInt **perms[32] = {NULL}; 7648 const PetscScalar **flips[32] = {NULL}; 7649 PetscScalar *valCopy = NULL; 7650 /* Hanging node constraints */ 7651 PetscInt *pointsC = NULL; 7652 PetscScalar *valuesC = NULL; 7653 PetscInt NclC, NiC; 7654 7655 PetscInt *idx; 7656 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7657 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7658 7659 PetscFunctionBeginHot; 7660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7661 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7662 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7663 if (numIndices) PetscAssertPointer(numIndices, 6); 7664 if (indices) PetscAssertPointer(indices, 7); 7665 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7666 if (values) PetscAssertPointer(values, 9); 7667 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7668 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7669 PetscCall(PetscArrayzero(offsets, 32)); 7670 /* 1) Get points in closure */ 7671 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7672 if (useClPerm) { 7673 PetscInt depth, clsize; 7674 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7675 for (clsize = 0, p = 0; p < Ncl; p++) { 7676 PetscInt dof; 7677 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7678 clsize += dof; 7679 } 7680 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7681 } 7682 /* 2) Get number of indices on these points and field offsets from section */ 7683 for (p = 0; p < Ncl * 2; p += 2) { 7684 PetscInt dof, fdof; 7685 7686 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7687 for (f = 0; f < Nf; ++f) { 7688 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7689 offsets[f + 1] += fdof; 7690 } 7691 Ni += dof; 7692 } 7693 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7694 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7695 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7696 for (f = 0; f < PetscMax(1, Nf); ++f) { 7697 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7698 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7699 /* may need to apply sign changes to the element matrix */ 7700 if (values && flips[f]) { 7701 PetscInt foffset = offsets[f]; 7702 7703 for (p = 0; p < Ncl; ++p) { 7704 PetscInt pnt = points[2 * p], fdof; 7705 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7706 7707 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7708 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7709 if (flip) { 7710 PetscInt i, j, k; 7711 7712 if (!valCopy) { 7713 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7714 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7715 *values = valCopy; 7716 } 7717 for (i = 0; i < fdof; ++i) { 7718 PetscScalar fval = flip[i]; 7719 7720 for (k = 0; k < Ni; ++k) { 7721 valCopy[Ni * (foffset + i) + k] *= fval; 7722 valCopy[Ni * k + (foffset + i)] *= fval; 7723 } 7724 } 7725 } 7726 foffset += fdof; 7727 } 7728 } 7729 } 7730 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7731 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7732 if (NclC) { 7733 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7734 for (f = 0; f < PetscMax(1, Nf); ++f) { 7735 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7736 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7737 } 7738 for (f = 0; f < PetscMax(1, Nf); ++f) { 7739 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7740 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7741 } 7742 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7743 Ncl = NclC; 7744 Ni = NiC; 7745 points = pointsC; 7746 if (values) *values = valuesC; 7747 } 7748 /* 5) Calculate indices */ 7749 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7750 if (Nf) { 7751 PetscInt idxOff; 7752 PetscBool useFieldOffsets; 7753 7754 if (outOffsets) { 7755 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7756 } 7757 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7758 if (useFieldOffsets) { 7759 for (p = 0; p < Ncl; ++p) { 7760 const PetscInt pnt = points[p * 2]; 7761 7762 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7763 } 7764 } else { 7765 for (p = 0; p < Ncl; ++p) { 7766 const PetscInt pnt = points[p * 2]; 7767 7768 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7769 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7770 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7771 * global section. */ 7772 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7773 } 7774 } 7775 } else { 7776 PetscInt off = 0, idxOff; 7777 7778 for (p = 0; p < Ncl; ++p) { 7779 const PetscInt pnt = points[p * 2]; 7780 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7781 7782 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7783 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7784 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7785 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7786 } 7787 } 7788 /* 6) Cleanup */ 7789 for (f = 0; f < PetscMax(1, Nf); ++f) { 7790 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7791 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7792 } 7793 if (NclC) { 7794 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7795 } else { 7796 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7797 } 7798 7799 if (numIndices) *numIndices = Ni; 7800 if (indices) *indices = idx; 7801 PetscFunctionReturn(PETSC_SUCCESS); 7802 } 7803 7804 /*@C 7805 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7806 7807 Not collective 7808 7809 Input Parameters: 7810 + dm - The `DM` 7811 . section - The `PetscSection` describing the points (a local section) 7812 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7813 . point - The point defining the closure 7814 - useClPerm - Use the closure point permutation if available 7815 7816 Output Parameters: 7817 + numIndices - The number of dof indices in the closure of point with the input sections 7818 . indices - The dof indices 7819 . outOffsets - Array to write the field offsets into, or `NULL` 7820 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7821 7822 Level: advanced 7823 7824 Notes: 7825 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7826 7827 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7828 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7829 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7830 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7831 indices (with the above semantics) are implied. 7832 7833 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7834 @*/ 7835 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7836 { 7837 PetscFunctionBegin; 7838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7839 PetscAssertPointer(indices, 7); 7840 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7841 PetscFunctionReturn(PETSC_SUCCESS); 7842 } 7843 7844 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7845 { 7846 DM_Plex *mesh = (DM_Plex *)dm->data; 7847 PetscInt *indices; 7848 PetscInt numIndices; 7849 const PetscScalar *valuesOrig = values; 7850 PetscErrorCode ierr; 7851 7852 PetscFunctionBegin; 7853 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7854 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7855 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7856 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7857 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7858 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 7859 7860 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7861 7862 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7863 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7864 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7865 if (ierr) { 7866 PetscMPIInt rank; 7867 7868 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7869 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7870 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7871 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7872 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7873 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7874 } 7875 if (mesh->printFEM > 1) { 7876 PetscInt i; 7877 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7878 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7879 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7880 } 7881 7882 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7883 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7884 PetscFunctionReturn(PETSC_SUCCESS); 7885 } 7886 7887 /*@C 7888 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7889 7890 Not collective 7891 7892 Input Parameters: 7893 + dm - The `DM` 7894 . section - The section describing the layout in `v`, or `NULL` to use the default section 7895 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 7896 . A - The matrix 7897 . point - The point in the `DM` 7898 . values - The array of values 7899 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7900 7901 Level: intermediate 7902 7903 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7904 @*/ 7905 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7906 { 7907 PetscFunctionBegin; 7908 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 7909 PetscFunctionReturn(PETSC_SUCCESS); 7910 } 7911 7912 /*@C 7913 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 7914 7915 Not collective 7916 7917 Input Parameters: 7918 + dmRow - The `DM` for the row fields 7919 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 7920 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 7921 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 7922 . dmCol - The `DM` for the column fields 7923 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 7924 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 7925 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 7926 . A - The matrix 7927 . point - The point in the `DM` 7928 . values - The array of values 7929 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7930 7931 Level: intermediate 7932 7933 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7934 @*/ 7935 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, PetscBool useRowPerm, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, PetscBool useColPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7936 { 7937 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7938 PetscInt *indicesRow, *indicesCol; 7939 PetscInt numIndicesRow, numIndicesCol; 7940 const PetscScalar *valuesOrig = values; 7941 PetscErrorCode ierr; 7942 7943 PetscFunctionBegin; 7944 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7945 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7946 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7947 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7948 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7949 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 7950 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7951 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 7952 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7953 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 7954 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 7955 7956 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7957 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7958 7959 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7960 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7961 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7962 if (ierr) { 7963 PetscMPIInt rank; 7964 7965 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7966 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7967 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7968 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7969 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7970 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7971 } 7972 7973 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7974 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7975 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7976 PetscFunctionReturn(PETSC_SUCCESS); 7977 } 7978 7979 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7980 { 7981 DM_Plex *mesh = (DM_Plex *)dmf->data; 7982 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7983 PetscInt *cpoints = NULL; 7984 PetscInt *findices, *cindices; 7985 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7986 PetscInt foffsets[32], coffsets[32]; 7987 DMPolytopeType ct; 7988 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7989 PetscErrorCode ierr; 7990 7991 PetscFunctionBegin; 7992 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7993 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7994 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7995 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7996 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7997 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7998 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7999 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8000 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8001 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8002 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8003 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8004 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8005 PetscCall(PetscArrayzero(foffsets, 32)); 8006 PetscCall(PetscArrayzero(coffsets, 32)); 8007 /* Column indices */ 8008 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8009 maxFPoints = numCPoints; 8010 /* Compress out points not in the section */ 8011 /* TODO: Squeeze out points with 0 dof as well */ 8012 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8013 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8014 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8015 cpoints[q * 2] = cpoints[p]; 8016 cpoints[q * 2 + 1] = cpoints[p + 1]; 8017 ++q; 8018 } 8019 } 8020 numCPoints = q; 8021 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8022 PetscInt fdof; 8023 8024 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8025 if (!dof) continue; 8026 for (f = 0; f < numFields; ++f) { 8027 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8028 coffsets[f + 1] += fdof; 8029 } 8030 numCIndices += dof; 8031 } 8032 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8033 /* Row indices */ 8034 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8035 { 8036 DMPlexTransform tr; 8037 DMPolytopeType *rct; 8038 PetscInt *rsize, *rcone, *rornt, Nt; 8039 8040 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8041 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8042 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8043 numSubcells = rsize[Nt - 1]; 8044 PetscCall(DMPlexTransformDestroy(&tr)); 8045 } 8046 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8047 for (r = 0, q = 0; r < numSubcells; ++r) { 8048 /* TODO Map from coarse to fine cells */ 8049 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8050 /* Compress out points not in the section */ 8051 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8052 for (p = 0; p < numFPoints * 2; p += 2) { 8053 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8054 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8055 if (!dof) continue; 8056 for (s = 0; s < q; ++s) 8057 if (fpoints[p] == ftotpoints[s * 2]) break; 8058 if (s < q) continue; 8059 ftotpoints[q * 2] = fpoints[p]; 8060 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8061 ++q; 8062 } 8063 } 8064 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8065 } 8066 numFPoints = q; 8067 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8068 PetscInt fdof; 8069 8070 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8071 if (!dof) continue; 8072 for (f = 0; f < numFields; ++f) { 8073 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8074 foffsets[f + 1] += fdof; 8075 } 8076 numFIndices += dof; 8077 } 8078 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8079 8080 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8081 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8082 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8083 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8084 if (numFields) { 8085 const PetscInt **permsF[32] = {NULL}; 8086 const PetscInt **permsC[32] = {NULL}; 8087 8088 for (f = 0; f < numFields; f++) { 8089 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8090 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8091 } 8092 for (p = 0; p < numFPoints; p++) { 8093 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8094 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8095 } 8096 for (p = 0; p < numCPoints; p++) { 8097 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8098 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8099 } 8100 for (f = 0; f < numFields; f++) { 8101 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8102 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8103 } 8104 } else { 8105 const PetscInt **permsF = NULL; 8106 const PetscInt **permsC = NULL; 8107 8108 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8109 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8110 for (p = 0, off = 0; p < numFPoints; p++) { 8111 const PetscInt *perm = permsF ? permsF[p] : NULL; 8112 8113 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8114 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8115 } 8116 for (p = 0, off = 0; p < numCPoints; p++) { 8117 const PetscInt *perm = permsC ? permsC[p] : NULL; 8118 8119 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8120 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8121 } 8122 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8123 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8124 } 8125 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8126 /* TODO: flips */ 8127 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8128 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8129 if (ierr) { 8130 PetscMPIInt rank; 8131 8132 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8133 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8134 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8135 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8136 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8137 } 8138 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8139 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8140 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8141 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8142 PetscFunctionReturn(PETSC_SUCCESS); 8143 } 8144 8145 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8146 { 8147 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8148 PetscInt *cpoints = NULL; 8149 PetscInt foffsets[32], coffsets[32]; 8150 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8151 DMPolytopeType ct; 8152 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8153 8154 PetscFunctionBegin; 8155 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8156 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8157 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8158 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8159 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8160 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8161 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8162 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8163 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8164 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8165 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8166 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8167 PetscCall(PetscArrayzero(foffsets, 32)); 8168 PetscCall(PetscArrayzero(coffsets, 32)); 8169 /* Column indices */ 8170 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8171 maxFPoints = numCPoints; 8172 /* Compress out points not in the section */ 8173 /* TODO: Squeeze out points with 0 dof as well */ 8174 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8175 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8176 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8177 cpoints[q * 2] = cpoints[p]; 8178 cpoints[q * 2 + 1] = cpoints[p + 1]; 8179 ++q; 8180 } 8181 } 8182 numCPoints = q; 8183 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8184 PetscInt fdof; 8185 8186 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8187 if (!dof) continue; 8188 for (f = 0; f < numFields; ++f) { 8189 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8190 coffsets[f + 1] += fdof; 8191 } 8192 numCIndices += dof; 8193 } 8194 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8195 /* Row indices */ 8196 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8197 { 8198 DMPlexTransform tr; 8199 DMPolytopeType *rct; 8200 PetscInt *rsize, *rcone, *rornt, Nt; 8201 8202 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8203 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8204 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8205 numSubcells = rsize[Nt - 1]; 8206 PetscCall(DMPlexTransformDestroy(&tr)); 8207 } 8208 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8209 for (r = 0, q = 0; r < numSubcells; ++r) { 8210 /* TODO Map from coarse to fine cells */ 8211 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8212 /* Compress out points not in the section */ 8213 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8214 for (p = 0; p < numFPoints * 2; p += 2) { 8215 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8216 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8217 if (!dof) continue; 8218 for (s = 0; s < q; ++s) 8219 if (fpoints[p] == ftotpoints[s * 2]) break; 8220 if (s < q) continue; 8221 ftotpoints[q * 2] = fpoints[p]; 8222 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8223 ++q; 8224 } 8225 } 8226 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8227 } 8228 numFPoints = q; 8229 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8230 PetscInt fdof; 8231 8232 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8233 if (!dof) continue; 8234 for (f = 0; f < numFields; ++f) { 8235 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8236 foffsets[f + 1] += fdof; 8237 } 8238 numFIndices += dof; 8239 } 8240 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8241 8242 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8243 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8244 if (numFields) { 8245 const PetscInt **permsF[32] = {NULL}; 8246 const PetscInt **permsC[32] = {NULL}; 8247 8248 for (f = 0; f < numFields; f++) { 8249 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8250 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8251 } 8252 for (p = 0; p < numFPoints; p++) { 8253 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8254 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8255 } 8256 for (p = 0; p < numCPoints; p++) { 8257 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8258 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8259 } 8260 for (f = 0; f < numFields; f++) { 8261 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8262 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8263 } 8264 } else { 8265 const PetscInt **permsF = NULL; 8266 const PetscInt **permsC = NULL; 8267 8268 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8269 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8270 for (p = 0, off = 0; p < numFPoints; p++) { 8271 const PetscInt *perm = permsF ? permsF[p] : NULL; 8272 8273 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8274 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8275 } 8276 for (p = 0, off = 0; p < numCPoints; p++) { 8277 const PetscInt *perm = permsC ? permsC[p] : NULL; 8278 8279 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8280 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8281 } 8282 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8283 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8284 } 8285 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8286 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8287 PetscFunctionReturn(PETSC_SUCCESS); 8288 } 8289 8290 /*@C 8291 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8292 8293 Input Parameter: 8294 . dm - The `DMPLEX` object 8295 8296 Output Parameter: 8297 . cellHeight - The height of a cell 8298 8299 Level: developer 8300 8301 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8302 @*/ 8303 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8304 { 8305 DM_Plex *mesh = (DM_Plex *)dm->data; 8306 8307 PetscFunctionBegin; 8308 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8309 PetscAssertPointer(cellHeight, 2); 8310 *cellHeight = mesh->vtkCellHeight; 8311 PetscFunctionReturn(PETSC_SUCCESS); 8312 } 8313 8314 /*@C 8315 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8316 8317 Input Parameters: 8318 + dm - The `DMPLEX` object 8319 - cellHeight - The height of a cell 8320 8321 Level: developer 8322 8323 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8324 @*/ 8325 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8326 { 8327 DM_Plex *mesh = (DM_Plex *)dm->data; 8328 8329 PetscFunctionBegin; 8330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8331 mesh->vtkCellHeight = cellHeight; 8332 PetscFunctionReturn(PETSC_SUCCESS); 8333 } 8334 8335 /*@ 8336 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8337 8338 Input Parameters: 8339 + dm - The `DMPLEX` object 8340 - ct - The `DMPolytopeType` of the cell 8341 8342 Output Parameters: 8343 + start - The first cell of this type, or `NULL` 8344 - end - The upper bound on this celltype, or `NULL` 8345 8346 Level: advanced 8347 8348 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8349 @*/ 8350 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8351 { 8352 DM_Plex *mesh = (DM_Plex *)dm->data; 8353 DMLabel label; 8354 PetscInt pStart, pEnd; 8355 8356 PetscFunctionBegin; 8357 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8358 if (start) { 8359 PetscAssertPointer(start, 3); 8360 *start = 0; 8361 } 8362 if (end) { 8363 PetscAssertPointer(end, 4); 8364 *end = 0; 8365 } 8366 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8367 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8368 if (mesh->tr) { 8369 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8370 } else { 8371 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8372 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8373 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8374 } 8375 PetscFunctionReturn(PETSC_SUCCESS); 8376 } 8377 8378 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8379 { 8380 PetscSection section, globalSection; 8381 PetscInt *numbers, p; 8382 8383 PetscFunctionBegin; 8384 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8385 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8386 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8387 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8388 PetscCall(PetscSectionSetUp(section)); 8389 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8390 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8391 for (p = pStart; p < pEnd; ++p) { 8392 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8393 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8394 else numbers[p - pStart] += shift; 8395 } 8396 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8397 if (globalSize) { 8398 PetscLayout layout; 8399 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8400 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8401 PetscCall(PetscLayoutDestroy(&layout)); 8402 } 8403 PetscCall(PetscSectionDestroy(§ion)); 8404 PetscCall(PetscSectionDestroy(&globalSection)); 8405 PetscFunctionReturn(PETSC_SUCCESS); 8406 } 8407 8408 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8409 { 8410 PetscInt cellHeight, cStart, cEnd; 8411 8412 PetscFunctionBegin; 8413 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8414 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8415 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8416 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8417 PetscFunctionReturn(PETSC_SUCCESS); 8418 } 8419 8420 /*@ 8421 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8422 8423 Input Parameter: 8424 . dm - The `DMPLEX` object 8425 8426 Output Parameter: 8427 . globalCellNumbers - Global cell numbers for all cells on this process 8428 8429 Level: developer 8430 8431 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8432 @*/ 8433 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8434 { 8435 DM_Plex *mesh = (DM_Plex *)dm->data; 8436 8437 PetscFunctionBegin; 8438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8439 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8440 *globalCellNumbers = mesh->globalCellNumbers; 8441 PetscFunctionReturn(PETSC_SUCCESS); 8442 } 8443 8444 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8445 { 8446 PetscInt vStart, vEnd; 8447 8448 PetscFunctionBegin; 8449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8450 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8451 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8452 PetscFunctionReturn(PETSC_SUCCESS); 8453 } 8454 8455 /*@ 8456 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8457 8458 Input Parameter: 8459 . dm - The `DMPLEX` object 8460 8461 Output Parameter: 8462 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8463 8464 Level: developer 8465 8466 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8467 @*/ 8468 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8469 { 8470 DM_Plex *mesh = (DM_Plex *)dm->data; 8471 8472 PetscFunctionBegin; 8473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8474 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8475 *globalVertexNumbers = mesh->globalVertexNumbers; 8476 PetscFunctionReturn(PETSC_SUCCESS); 8477 } 8478 8479 /*@ 8480 DMPlexCreatePointNumbering - Create a global numbering for all points. 8481 8482 Collective 8483 8484 Input Parameter: 8485 . dm - The `DMPLEX` object 8486 8487 Output Parameter: 8488 . globalPointNumbers - Global numbers for all points on this process 8489 8490 Level: developer 8491 8492 Notes: 8493 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8494 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8495 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8496 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8497 8498 The partitioned mesh is 8499 ``` 8500 (2)--0--(3)--1--(4) (1)--0--(2) 8501 ``` 8502 and its global numbering is 8503 ``` 8504 (3)--0--(4)--1--(5)--2--(6) 8505 ``` 8506 Then the global numbering is provided as 8507 ``` 8508 [0] Number of indices in set 5 8509 [0] 0 0 8510 [0] 1 1 8511 [0] 2 3 8512 [0] 3 4 8513 [0] 4 -6 8514 [1] Number of indices in set 3 8515 [1] 0 2 8516 [1] 1 5 8517 [1] 2 6 8518 ``` 8519 8520 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8521 @*/ 8522 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8523 { 8524 IS nums[4]; 8525 PetscInt depths[4], gdepths[4], starts[4]; 8526 PetscInt depth, d, shift = 0; 8527 PetscBool empty = PETSC_FALSE; 8528 8529 PetscFunctionBegin; 8530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8531 PetscCall(DMPlexGetDepth(dm, &depth)); 8532 // For unstratified meshes use dim instead of depth 8533 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8534 // If any stratum is empty, we must mark all empty 8535 for (d = 0; d <= depth; ++d) { 8536 PetscInt end; 8537 8538 depths[d] = depth - d; 8539 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8540 if (!(starts[d] - end)) empty = PETSC_TRUE; 8541 } 8542 if (empty) 8543 for (d = 0; d <= depth; ++d) { 8544 depths[d] = -1; 8545 starts[d] = -1; 8546 } 8547 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8548 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8549 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]); 8550 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8551 for (d = 0; d <= depth; ++d) { 8552 PetscInt pStart, pEnd, gsize; 8553 8554 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8555 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8556 shift += gsize; 8557 } 8558 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8559 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8560 PetscFunctionReturn(PETSC_SUCCESS); 8561 } 8562 8563 /*@ 8564 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8565 8566 Input Parameter: 8567 . dm - The `DMPLEX` object 8568 8569 Output Parameter: 8570 . ranks - The rank field 8571 8572 Options Database Key: 8573 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8574 8575 Level: intermediate 8576 8577 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8578 @*/ 8579 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8580 { 8581 DM rdm; 8582 PetscFE fe; 8583 PetscScalar *r; 8584 PetscMPIInt rank; 8585 DMPolytopeType ct; 8586 PetscInt dim, cStart, cEnd, c; 8587 PetscBool simplex; 8588 8589 PetscFunctionBeginUser; 8590 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8591 PetscAssertPointer(ranks, 2); 8592 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8593 PetscCall(DMClone(dm, &rdm)); 8594 PetscCall(DMGetDimension(rdm, &dim)); 8595 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8596 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8597 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8598 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8599 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8600 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8601 PetscCall(PetscFEDestroy(&fe)); 8602 PetscCall(DMCreateDS(rdm)); 8603 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8604 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8605 PetscCall(VecGetArray(*ranks, &r)); 8606 for (c = cStart; c < cEnd; ++c) { 8607 PetscScalar *lr; 8608 8609 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8610 if (lr) *lr = rank; 8611 } 8612 PetscCall(VecRestoreArray(*ranks, &r)); 8613 PetscCall(DMDestroy(&rdm)); 8614 PetscFunctionReturn(PETSC_SUCCESS); 8615 } 8616 8617 /*@ 8618 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8619 8620 Input Parameters: 8621 + dm - The `DMPLEX` 8622 - label - The `DMLabel` 8623 8624 Output Parameter: 8625 . val - The label value field 8626 8627 Options Database Key: 8628 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8629 8630 Level: intermediate 8631 8632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8633 @*/ 8634 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8635 { 8636 DM rdm; 8637 PetscFE fe; 8638 PetscScalar *v; 8639 PetscInt dim, cStart, cEnd, c; 8640 8641 PetscFunctionBeginUser; 8642 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8643 PetscAssertPointer(label, 2); 8644 PetscAssertPointer(val, 3); 8645 PetscCall(DMClone(dm, &rdm)); 8646 PetscCall(DMGetDimension(rdm, &dim)); 8647 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8648 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8649 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8650 PetscCall(PetscFEDestroy(&fe)); 8651 PetscCall(DMCreateDS(rdm)); 8652 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8653 PetscCall(DMCreateGlobalVector(rdm, val)); 8654 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8655 PetscCall(VecGetArray(*val, &v)); 8656 for (c = cStart; c < cEnd; ++c) { 8657 PetscScalar *lv; 8658 PetscInt cval; 8659 8660 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8661 PetscCall(DMLabelGetValue(label, c, &cval)); 8662 *lv = cval; 8663 } 8664 PetscCall(VecRestoreArray(*val, &v)); 8665 PetscCall(DMDestroy(&rdm)); 8666 PetscFunctionReturn(PETSC_SUCCESS); 8667 } 8668 8669 /*@ 8670 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8671 8672 Input Parameter: 8673 . dm - The `DMPLEX` object 8674 8675 Level: developer 8676 8677 Notes: 8678 This is a useful diagnostic when creating meshes programmatically. 8679 8680 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8681 8682 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8683 @*/ 8684 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8685 { 8686 PetscSection coneSection, supportSection; 8687 const PetscInt *cone, *support; 8688 PetscInt coneSize, c, supportSize, s; 8689 PetscInt pStart, pEnd, p, pp, csize, ssize; 8690 PetscBool storagecheck = PETSC_TRUE; 8691 8692 PetscFunctionBegin; 8693 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8694 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8695 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8696 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8697 /* Check that point p is found in the support of its cone points, and vice versa */ 8698 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8699 for (p = pStart; p < pEnd; ++p) { 8700 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8701 PetscCall(DMPlexGetCone(dm, p, &cone)); 8702 for (c = 0; c < coneSize; ++c) { 8703 PetscBool dup = PETSC_FALSE; 8704 PetscInt d; 8705 for (d = c - 1; d >= 0; --d) { 8706 if (cone[c] == cone[d]) { 8707 dup = PETSC_TRUE; 8708 break; 8709 } 8710 } 8711 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8712 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8713 for (s = 0; s < supportSize; ++s) { 8714 if (support[s] == p) break; 8715 } 8716 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8717 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8718 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8719 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8720 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8721 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8722 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8723 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]); 8724 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8725 } 8726 } 8727 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8728 if (p != pp) { 8729 storagecheck = PETSC_FALSE; 8730 continue; 8731 } 8732 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8733 PetscCall(DMPlexGetSupport(dm, p, &support)); 8734 for (s = 0; s < supportSize; ++s) { 8735 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8736 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8737 for (c = 0; c < coneSize; ++c) { 8738 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8739 if (cone[c] != pp) { 8740 c = 0; 8741 break; 8742 } 8743 if (cone[c] == p) break; 8744 } 8745 if (c >= coneSize) { 8746 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8747 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8748 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8749 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8750 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8751 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8752 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8753 } 8754 } 8755 } 8756 if (storagecheck) { 8757 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8758 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8759 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8760 } 8761 PetscFunctionReturn(PETSC_SUCCESS); 8762 } 8763 8764 /* 8765 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. 8766 */ 8767 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8768 { 8769 DMPolytopeType cct; 8770 PetscInt ptpoints[4]; 8771 const PetscInt *cone, *ccone, *ptcone; 8772 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8773 8774 PetscFunctionBegin; 8775 *unsplit = 0; 8776 switch (ct) { 8777 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8778 ptpoints[npt++] = c; 8779 break; 8780 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8781 PetscCall(DMPlexGetCone(dm, c, &cone)); 8782 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8783 for (cp = 0; cp < coneSize; ++cp) { 8784 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8785 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8786 } 8787 break; 8788 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8789 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8790 PetscCall(DMPlexGetCone(dm, c, &cone)); 8791 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8792 for (cp = 0; cp < coneSize; ++cp) { 8793 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8794 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8795 for (ccp = 0; ccp < cconeSize; ++ccp) { 8796 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8797 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8798 PetscInt p; 8799 for (p = 0; p < npt; ++p) 8800 if (ptpoints[p] == ccone[ccp]) break; 8801 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8802 } 8803 } 8804 } 8805 break; 8806 default: 8807 break; 8808 } 8809 for (pt = 0; pt < npt; ++pt) { 8810 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8811 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8812 } 8813 PetscFunctionReturn(PETSC_SUCCESS); 8814 } 8815 8816 /*@ 8817 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8818 8819 Input Parameters: 8820 + dm - The `DMPLEX` object 8821 - cellHeight - Normally 0 8822 8823 Level: developer 8824 8825 Notes: 8826 This is a useful diagnostic when creating meshes programmatically. 8827 Currently applicable only to homogeneous simplex or tensor meshes. 8828 8829 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8830 8831 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8832 @*/ 8833 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8834 { 8835 DMPlexInterpolatedFlag interp; 8836 DMPolytopeType ct; 8837 PetscInt vStart, vEnd, cStart, cEnd, c; 8838 8839 PetscFunctionBegin; 8840 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8841 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8842 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8843 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8844 for (c = cStart; c < cEnd; ++c) { 8845 PetscInt *closure = NULL; 8846 PetscInt coneSize, closureSize, cl, Nv = 0; 8847 8848 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8849 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8850 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8851 if (interp == DMPLEX_INTERPOLATED_FULL) { 8852 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8853 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)); 8854 } 8855 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8856 for (cl = 0; cl < closureSize * 2; cl += 2) { 8857 const PetscInt p = closure[cl]; 8858 if ((p >= vStart) && (p < vEnd)) ++Nv; 8859 } 8860 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8861 /* Special Case: Tensor faces with identified vertices */ 8862 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8863 PetscInt unsplit; 8864 8865 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8866 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8867 } 8868 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)); 8869 } 8870 PetscFunctionReturn(PETSC_SUCCESS); 8871 } 8872 8873 /*@ 8874 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8875 8876 Collective 8877 8878 Input Parameters: 8879 + dm - The `DMPLEX` object 8880 - cellHeight - Normally 0 8881 8882 Level: developer 8883 8884 Notes: 8885 This is a useful diagnostic when creating meshes programmatically. 8886 This routine is only relevant for meshes that are fully interpolated across all ranks. 8887 It will error out if a partially interpolated mesh is given on some rank. 8888 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8889 8890 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8891 8892 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8893 @*/ 8894 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8895 { 8896 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8897 DMPlexInterpolatedFlag interpEnum; 8898 8899 PetscFunctionBegin; 8900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8901 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8902 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 8903 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8904 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 8905 PetscFunctionReturn(PETSC_SUCCESS); 8906 } 8907 8908 PetscCall(DMGetDimension(dm, &dim)); 8909 PetscCall(DMPlexGetDepth(dm, &depth)); 8910 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8911 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8912 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8913 for (c = cStart; c < cEnd; ++c) { 8914 const PetscInt *cone, *ornt, *faceSizes, *faces; 8915 const DMPolytopeType *faceTypes; 8916 DMPolytopeType ct; 8917 PetscInt numFaces, coneSize, f; 8918 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8919 8920 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8921 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8922 if (unsplit) continue; 8923 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8924 PetscCall(DMPlexGetCone(dm, c, &cone)); 8925 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8926 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8927 for (cl = 0; cl < closureSize * 2; cl += 2) { 8928 const PetscInt p = closure[cl]; 8929 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8930 } 8931 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8932 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); 8933 for (f = 0; f < numFaces; ++f) { 8934 DMPolytopeType fct; 8935 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8936 8937 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8938 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8939 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8940 const PetscInt p = fclosure[cl]; 8941 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8942 } 8943 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]); 8944 for (v = 0; v < fnumCorners; ++v) { 8945 if (fclosure[v] != faces[fOff + v]) { 8946 PetscInt v1; 8947 8948 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8949 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8950 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8951 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8952 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8953 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]); 8954 } 8955 } 8956 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8957 fOff += faceSizes[f]; 8958 } 8959 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8960 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8961 } 8962 } 8963 PetscFunctionReturn(PETSC_SUCCESS); 8964 } 8965 8966 /*@ 8967 DMPlexCheckGeometry - Check the geometry of mesh cells 8968 8969 Input Parameter: 8970 . dm - The `DMPLEX` object 8971 8972 Level: developer 8973 8974 Notes: 8975 This is a useful diagnostic when creating meshes programmatically. 8976 8977 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8978 8979 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8980 @*/ 8981 PetscErrorCode DMPlexCheckGeometry(DM dm) 8982 { 8983 Vec coordinates; 8984 PetscReal detJ, J[9], refVol = 1.0; 8985 PetscReal vol; 8986 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8987 8988 PetscFunctionBegin; 8989 PetscCall(DMGetDimension(dm, &dim)); 8990 PetscCall(DMGetCoordinateDim(dm, &dE)); 8991 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 8992 PetscCall(DMPlexGetDepth(dm, &depth)); 8993 for (d = 0; d < dim; ++d) refVol *= 2.0; 8994 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8995 /* Make sure local coordinates are created, because that step is collective */ 8996 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8997 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 8998 for (c = cStart; c < cEnd; ++c) { 8999 DMPolytopeType ct; 9000 PetscInt unsplit; 9001 PetscBool ignoreZeroVol = PETSC_FALSE; 9002 9003 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9004 switch (ct) { 9005 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9006 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9007 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9008 ignoreZeroVol = PETSC_TRUE; 9009 break; 9010 default: 9011 break; 9012 } 9013 switch (ct) { 9014 case DM_POLYTOPE_TRI_PRISM: 9015 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9016 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9017 case DM_POLYTOPE_PYRAMID: 9018 continue; 9019 default: 9020 break; 9021 } 9022 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9023 if (unsplit) continue; 9024 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9025 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); 9026 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9027 /* This should work with periodicity since DG coordinates should be used */ 9028 if (depth > 1) { 9029 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9030 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); 9031 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9032 } 9033 } 9034 PetscFunctionReturn(PETSC_SUCCESS); 9035 } 9036 9037 /*@ 9038 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9039 9040 Collective 9041 9042 Input Parameters: 9043 + dm - The `DMPLEX` object 9044 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9045 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9046 9047 Level: developer 9048 9049 Notes: 9050 This is mainly intended for debugging/testing purposes. 9051 9052 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9053 9054 Extra roots can come from priodic cuts, where additional points appear on the boundary 9055 9056 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9057 @*/ 9058 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9059 { 9060 PetscInt l, nleaves, nroots, overlap; 9061 const PetscInt *locals; 9062 const PetscSFNode *remotes; 9063 PetscBool distributed; 9064 MPI_Comm comm; 9065 PetscMPIInt rank; 9066 9067 PetscFunctionBegin; 9068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9069 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9070 else pointSF = dm->sf; 9071 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9072 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9073 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9074 { 9075 PetscMPIInt mpiFlag; 9076 9077 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9078 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9079 } 9080 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9081 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9082 if (!distributed) { 9083 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); 9084 PetscFunctionReturn(PETSC_SUCCESS); 9085 } 9086 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); 9087 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9088 9089 /* Check SF graph is compatible with DMPlex chart */ 9090 { 9091 PetscInt pStart, pEnd, maxLeaf; 9092 9093 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9094 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9095 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9096 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9097 } 9098 9099 /* Check Point SF has no local points referenced */ 9100 for (l = 0; l < nleaves; l++) { 9101 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); 9102 } 9103 9104 /* Check there are no cells in interface */ 9105 if (!overlap) { 9106 PetscInt cellHeight, cStart, cEnd; 9107 9108 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9109 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9110 for (l = 0; l < nleaves; ++l) { 9111 const PetscInt point = locals ? locals[l] : l; 9112 9113 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9114 } 9115 } 9116 9117 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9118 { 9119 const PetscInt *rootdegree; 9120 9121 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9122 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9123 for (l = 0; l < nleaves; ++l) { 9124 const PetscInt point = locals ? locals[l] : l; 9125 const PetscInt *cone; 9126 PetscInt coneSize, c, idx; 9127 9128 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9129 PetscCall(DMPlexGetCone(dm, point, &cone)); 9130 for (c = 0; c < coneSize; ++c) { 9131 if (!rootdegree[cone[c]]) { 9132 if (locals) { 9133 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9134 } else { 9135 idx = (cone[c] < nleaves) ? cone[c] : -1; 9136 } 9137 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9138 } 9139 } 9140 } 9141 } 9142 PetscFunctionReturn(PETSC_SUCCESS); 9143 } 9144 9145 /*@ 9146 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9147 9148 Input Parameter: 9149 . dm - The `DMPLEX` object 9150 9151 Level: developer 9152 9153 Notes: 9154 This is a useful diagnostic when creating meshes programmatically. 9155 9156 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9157 9158 Currently does not include `DMPlexCheckCellShape()`. 9159 9160 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9161 @*/ 9162 PetscErrorCode DMPlexCheck(DM dm) 9163 { 9164 PetscInt cellHeight; 9165 9166 PetscFunctionBegin; 9167 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9168 PetscCall(DMPlexCheckSymmetry(dm)); 9169 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9170 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9171 PetscCall(DMPlexCheckGeometry(dm)); 9172 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9173 PetscCall(DMPlexCheckInterfaceCones(dm)); 9174 PetscFunctionReturn(PETSC_SUCCESS); 9175 } 9176 9177 typedef struct cell_stats { 9178 PetscReal min, max, sum, squaresum; 9179 PetscInt count; 9180 } cell_stats_t; 9181 9182 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9183 { 9184 PetscInt i, N = *len; 9185 9186 for (i = 0; i < N; i++) { 9187 cell_stats_t *A = (cell_stats_t *)a; 9188 cell_stats_t *B = (cell_stats_t *)b; 9189 9190 B->min = PetscMin(A->min, B->min); 9191 B->max = PetscMax(A->max, B->max); 9192 B->sum += A->sum; 9193 B->squaresum += A->squaresum; 9194 B->count += A->count; 9195 } 9196 } 9197 9198 /*@ 9199 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9200 9201 Collective 9202 9203 Input Parameters: 9204 + dm - The `DMPLEX` object 9205 . output - If true, statistics will be displayed on `stdout` 9206 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9207 9208 Level: developer 9209 9210 Notes: 9211 This is mainly intended for debugging/testing purposes. 9212 9213 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9214 9215 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9216 @*/ 9217 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9218 { 9219 DM dmCoarse; 9220 cell_stats_t stats, globalStats; 9221 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9222 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9223 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9224 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9225 PetscMPIInt rank, size; 9226 9227 PetscFunctionBegin; 9228 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9229 stats.min = PETSC_MAX_REAL; 9230 stats.max = PETSC_MIN_REAL; 9231 stats.sum = stats.squaresum = 0.; 9232 stats.count = 0; 9233 9234 PetscCallMPI(MPI_Comm_size(comm, &size)); 9235 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9236 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9237 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9238 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9239 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9240 for (c = cStart; c < cEnd; c++) { 9241 PetscInt i; 9242 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9243 9244 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9245 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9246 for (i = 0; i < PetscSqr(cdim); ++i) { 9247 frobJ += J[i] * J[i]; 9248 frobInvJ += invJ[i] * invJ[i]; 9249 } 9250 cond2 = frobJ * frobInvJ; 9251 cond = PetscSqrtReal(cond2); 9252 9253 stats.min = PetscMin(stats.min, cond); 9254 stats.max = PetscMax(stats.max, cond); 9255 stats.sum += cond; 9256 stats.squaresum += cond2; 9257 stats.count++; 9258 if (output && cond > limit) { 9259 PetscSection coordSection; 9260 Vec coordsLocal; 9261 PetscScalar *coords = NULL; 9262 PetscInt Nv, d, clSize, cl, *closure = NULL; 9263 9264 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9265 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9266 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9267 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9268 for (i = 0; i < Nv / cdim; ++i) { 9269 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9270 for (d = 0; d < cdim; ++d) { 9271 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9272 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9273 } 9274 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9275 } 9276 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9277 for (cl = 0; cl < clSize * 2; cl += 2) { 9278 const PetscInt edge = closure[cl]; 9279 9280 if ((edge >= eStart) && (edge < eEnd)) { 9281 PetscReal len; 9282 9283 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9284 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9285 } 9286 } 9287 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9288 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9289 } 9290 } 9291 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9292 9293 if (size > 1) { 9294 PetscMPIInt blockLengths[2] = {4, 1}; 9295 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9296 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9297 MPI_Op statReduce; 9298 9299 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9300 PetscCallMPI(MPI_Type_commit(&statType)); 9301 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9302 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9303 PetscCallMPI(MPI_Op_free(&statReduce)); 9304 PetscCallMPI(MPI_Type_free(&statType)); 9305 } else { 9306 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9307 } 9308 if (rank == 0) { 9309 count = globalStats.count; 9310 min = globalStats.min; 9311 max = globalStats.max; 9312 mean = globalStats.sum / globalStats.count; 9313 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9314 } 9315 9316 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)); 9317 PetscCall(PetscFree2(J, invJ)); 9318 9319 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9320 if (dmCoarse) { 9321 PetscBool isplex; 9322 9323 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9324 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9325 } 9326 PetscFunctionReturn(PETSC_SUCCESS); 9327 } 9328 9329 /*@ 9330 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9331 orthogonal quality below given tolerance. 9332 9333 Collective 9334 9335 Input Parameters: 9336 + dm - The `DMPLEX` object 9337 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9338 - atol - [0, 1] Absolute tolerance for tagging cells. 9339 9340 Output Parameters: 9341 + OrthQual - `Vec` containing orthogonal quality per cell 9342 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9343 9344 Options Database Keys: 9345 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9346 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9347 9348 Level: intermediate 9349 9350 Notes: 9351 Orthogonal quality is given by the following formula\: 9352 9353 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9354 9355 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 9356 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9357 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9358 calculating the cosine of the angle between these vectors. 9359 9360 Orthogonal quality ranges from 1 (best) to 0 (worst). 9361 9362 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9363 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9364 9365 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9366 9367 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9368 @*/ 9369 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9370 { 9371 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9372 PetscInt *idx; 9373 PetscScalar *oqVals; 9374 const PetscScalar *cellGeomArr, *faceGeomArr; 9375 PetscReal *ci, *fi, *Ai; 9376 MPI_Comm comm; 9377 Vec cellgeom, facegeom; 9378 DM dmFace, dmCell; 9379 IS glob; 9380 ISLocalToGlobalMapping ltog; 9381 PetscViewer vwr; 9382 9383 PetscFunctionBegin; 9384 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9385 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9386 PetscAssertPointer(OrthQual, 4); 9387 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9388 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9389 PetscCall(DMGetDimension(dm, &nc)); 9390 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9391 { 9392 DMPlexInterpolatedFlag interpFlag; 9393 9394 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9395 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9396 PetscMPIInt rank; 9397 9398 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9399 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9400 } 9401 } 9402 if (OrthQualLabel) { 9403 PetscAssertPointer(OrthQualLabel, 5); 9404 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9405 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9406 } else { 9407 *OrthQualLabel = NULL; 9408 } 9409 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9410 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9411 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9412 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9413 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9414 PetscCall(VecCreate(comm, OrthQual)); 9415 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9416 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9417 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9418 PetscCall(VecSetUp(*OrthQual)); 9419 PetscCall(ISDestroy(&glob)); 9420 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9421 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9422 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9423 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9424 PetscCall(VecGetDM(cellgeom, &dmCell)); 9425 PetscCall(VecGetDM(facegeom, &dmFace)); 9426 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9427 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9428 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9429 PetscInt cellarr[2], *adj = NULL; 9430 PetscScalar *cArr, *fArr; 9431 PetscReal minvalc = 1.0, minvalf = 1.0; 9432 PetscFVCellGeom *cg; 9433 9434 idx[cellIter] = cell - cStart; 9435 cellarr[0] = cell; 9436 /* Make indexing into cellGeom easier */ 9437 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9438 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9439 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9440 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9441 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9442 PetscInt i; 9443 const PetscInt neigh = adj[cellneigh]; 9444 PetscReal normci = 0, normfi = 0, normai = 0; 9445 PetscFVCellGeom *cgneigh; 9446 PetscFVFaceGeom *fg; 9447 9448 /* Don't count ourselves in the neighbor list */ 9449 if (neigh == cell) continue; 9450 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9451 cellarr[1] = neigh; 9452 { 9453 PetscInt numcovpts; 9454 const PetscInt *covpts; 9455 9456 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9457 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9458 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9459 } 9460 9461 /* Compute c_i, f_i and their norms */ 9462 for (i = 0; i < nc; i++) { 9463 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9464 fi[i] = fg->centroid[i] - cg->centroid[i]; 9465 Ai[i] = fg->normal[i]; 9466 normci += PetscPowReal(ci[i], 2); 9467 normfi += PetscPowReal(fi[i], 2); 9468 normai += PetscPowReal(Ai[i], 2); 9469 } 9470 normci = PetscSqrtReal(normci); 9471 normfi = PetscSqrtReal(normfi); 9472 normai = PetscSqrtReal(normai); 9473 9474 /* Normalize and compute for each face-cell-normal pair */ 9475 for (i = 0; i < nc; i++) { 9476 ci[i] = ci[i] / normci; 9477 fi[i] = fi[i] / normfi; 9478 Ai[i] = Ai[i] / normai; 9479 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9480 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9481 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9482 } 9483 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9484 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9485 } 9486 PetscCall(PetscFree(adj)); 9487 PetscCall(PetscFree2(cArr, fArr)); 9488 /* Defer to cell if they're equal */ 9489 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9490 if (OrthQualLabel) { 9491 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9492 } 9493 } 9494 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9495 PetscCall(VecAssemblyBegin(*OrthQual)); 9496 PetscCall(VecAssemblyEnd(*OrthQual)); 9497 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9498 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9499 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9500 if (OrthQualLabel) { 9501 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9502 } 9503 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9504 PetscCall(PetscViewerDestroy(&vwr)); 9505 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9506 PetscFunctionReturn(PETSC_SUCCESS); 9507 } 9508 9509 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9510 * interpolator construction */ 9511 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9512 { 9513 PetscSection section, newSection, gsection; 9514 PetscSF sf; 9515 PetscBool hasConstraints, ghasConstraints; 9516 9517 PetscFunctionBegin; 9518 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9519 PetscAssertPointer(odm, 2); 9520 PetscCall(DMGetLocalSection(dm, §ion)); 9521 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9522 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9523 if (!ghasConstraints) { 9524 PetscCall(PetscObjectReference((PetscObject)dm)); 9525 *odm = dm; 9526 PetscFunctionReturn(PETSC_SUCCESS); 9527 } 9528 PetscCall(DMClone(dm, odm)); 9529 PetscCall(DMCopyFields(dm, *odm)); 9530 PetscCall(DMGetLocalSection(*odm, &newSection)); 9531 PetscCall(DMGetPointSF(*odm, &sf)); 9532 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9533 PetscCall(DMSetGlobalSection(*odm, gsection)); 9534 PetscCall(PetscSectionDestroy(&gsection)); 9535 PetscFunctionReturn(PETSC_SUCCESS); 9536 } 9537 9538 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9539 { 9540 DM dmco, dmfo; 9541 Mat interpo; 9542 Vec rscale; 9543 Vec cglobalo, clocal; 9544 Vec fglobal, fglobalo, flocal; 9545 PetscBool regular; 9546 9547 PetscFunctionBegin; 9548 PetscCall(DMGetFullDM(dmc, &dmco)); 9549 PetscCall(DMGetFullDM(dmf, &dmfo)); 9550 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9551 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9552 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9553 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9554 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9555 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9556 PetscCall(VecSet(cglobalo, 0.)); 9557 PetscCall(VecSet(clocal, 0.)); 9558 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9559 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9560 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9561 PetscCall(VecSet(fglobal, 0.)); 9562 PetscCall(VecSet(fglobalo, 0.)); 9563 PetscCall(VecSet(flocal, 0.)); 9564 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9565 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9566 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9567 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9568 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9569 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9570 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9571 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9572 *shift = fglobal; 9573 PetscCall(VecDestroy(&flocal)); 9574 PetscCall(VecDestroy(&fglobalo)); 9575 PetscCall(VecDestroy(&clocal)); 9576 PetscCall(VecDestroy(&cglobalo)); 9577 PetscCall(VecDestroy(&rscale)); 9578 PetscCall(MatDestroy(&interpo)); 9579 PetscCall(DMDestroy(&dmfo)); 9580 PetscCall(DMDestroy(&dmco)); 9581 PetscFunctionReturn(PETSC_SUCCESS); 9582 } 9583 9584 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9585 { 9586 PetscObject shifto; 9587 Vec shift; 9588 9589 PetscFunctionBegin; 9590 if (!interp) { 9591 Vec rscale; 9592 9593 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9594 PetscCall(VecDestroy(&rscale)); 9595 } else { 9596 PetscCall(PetscObjectReference((PetscObject)interp)); 9597 } 9598 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9599 if (!shifto) { 9600 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9601 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9602 shifto = (PetscObject)shift; 9603 PetscCall(VecDestroy(&shift)); 9604 } 9605 shift = (Vec)shifto; 9606 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9607 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9608 PetscCall(MatDestroy(&interp)); 9609 PetscFunctionReturn(PETSC_SUCCESS); 9610 } 9611 9612 /* Pointwise interpolation 9613 Just code FEM for now 9614 u^f = I u^c 9615 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9616 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9617 I_{ij} = psi^f_i phi^c_j 9618 */ 9619 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9620 { 9621 PetscSection gsc, gsf; 9622 PetscInt m, n; 9623 void *ctx; 9624 DM cdm; 9625 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9626 9627 PetscFunctionBegin; 9628 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9629 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9630 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9631 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9632 9633 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9634 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9635 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9636 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9637 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9638 9639 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9640 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9641 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9642 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9643 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9644 if (scaling) { 9645 /* Use naive scaling */ 9646 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9647 } 9648 PetscFunctionReturn(PETSC_SUCCESS); 9649 } 9650 9651 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9652 { 9653 VecScatter ctx; 9654 9655 PetscFunctionBegin; 9656 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9657 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9658 PetscCall(VecScatterDestroy(&ctx)); 9659 PetscFunctionReturn(PETSC_SUCCESS); 9660 } 9661 9662 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[]) 9663 { 9664 const PetscInt Nc = uOff[1] - uOff[0]; 9665 PetscInt c; 9666 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9667 } 9668 9669 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9670 { 9671 DM dmc; 9672 PetscDS ds; 9673 Vec ones, locmass; 9674 IS cellIS; 9675 PetscFormKey key; 9676 PetscInt depth; 9677 9678 PetscFunctionBegin; 9679 PetscCall(DMClone(dm, &dmc)); 9680 PetscCall(DMCopyDisc(dm, dmc)); 9681 PetscCall(DMGetDS(dmc, &ds)); 9682 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9683 PetscCall(DMCreateGlobalVector(dmc, mass)); 9684 PetscCall(DMGetLocalVector(dmc, &ones)); 9685 PetscCall(DMGetLocalVector(dmc, &locmass)); 9686 PetscCall(DMPlexGetDepth(dmc, &depth)); 9687 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9688 PetscCall(VecSet(locmass, 0.0)); 9689 PetscCall(VecSet(ones, 1.0)); 9690 key.label = NULL; 9691 key.value = 0; 9692 key.field = 0; 9693 key.part = 0; 9694 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9695 PetscCall(ISDestroy(&cellIS)); 9696 PetscCall(VecSet(*mass, 0.0)); 9697 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9698 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9699 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9700 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9701 PetscCall(DMDestroy(&dmc)); 9702 PetscFunctionReturn(PETSC_SUCCESS); 9703 } 9704 9705 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9706 { 9707 PetscSection gsc, gsf; 9708 PetscInt m, n; 9709 void *ctx; 9710 DM cdm; 9711 PetscBool regular; 9712 9713 PetscFunctionBegin; 9714 if (dmFine == dmCoarse) { 9715 DM dmc; 9716 PetscDS ds; 9717 PetscWeakForm wf; 9718 Vec u; 9719 IS cellIS; 9720 PetscFormKey key; 9721 PetscInt depth; 9722 9723 PetscCall(DMClone(dmFine, &dmc)); 9724 PetscCall(DMCopyDisc(dmFine, dmc)); 9725 PetscCall(DMGetDS(dmc, &ds)); 9726 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9727 PetscCall(PetscWeakFormClear(wf)); 9728 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9729 PetscCall(DMCreateMatrix(dmc, mass)); 9730 PetscCall(DMGetLocalVector(dmc, &u)); 9731 PetscCall(DMPlexGetDepth(dmc, &depth)); 9732 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9733 PetscCall(MatZeroEntries(*mass)); 9734 key.label = NULL; 9735 key.value = 0; 9736 key.field = 0; 9737 key.part = 0; 9738 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9739 PetscCall(ISDestroy(&cellIS)); 9740 PetscCall(DMRestoreLocalVector(dmc, &u)); 9741 PetscCall(DMDestroy(&dmc)); 9742 } else { 9743 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9744 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9745 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9746 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9747 9748 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9749 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9750 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9751 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9752 9753 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9754 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9755 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9756 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9757 } 9758 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9759 PetscFunctionReturn(PETSC_SUCCESS); 9760 } 9761 9762 /*@ 9763 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9764 9765 Input Parameter: 9766 . dm - The `DMPLEX` object 9767 9768 Output Parameter: 9769 . regular - The flag 9770 9771 Level: intermediate 9772 9773 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9774 @*/ 9775 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9776 { 9777 PetscFunctionBegin; 9778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9779 PetscAssertPointer(regular, 2); 9780 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9781 PetscFunctionReturn(PETSC_SUCCESS); 9782 } 9783 9784 /*@ 9785 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9786 9787 Input Parameters: 9788 + dm - The `DMPLEX` object 9789 - regular - The flag 9790 9791 Level: intermediate 9792 9793 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9794 @*/ 9795 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9796 { 9797 PetscFunctionBegin; 9798 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9799 ((DM_Plex *)dm->data)->regularRefinement = regular; 9800 PetscFunctionReturn(PETSC_SUCCESS); 9801 } 9802 9803 /*@ 9804 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9805 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9806 9807 Not Collective 9808 9809 Input Parameter: 9810 . dm - The `DMPLEX` object 9811 9812 Output Parameters: 9813 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9814 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9815 9816 Level: intermediate 9817 9818 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9819 @*/ 9820 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9821 { 9822 DM_Plex *plex = (DM_Plex *)dm->data; 9823 9824 PetscFunctionBegin; 9825 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9826 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9827 if (anchorSection) *anchorSection = plex->anchorSection; 9828 if (anchorIS) *anchorIS = plex->anchorIS; 9829 PetscFunctionReturn(PETSC_SUCCESS); 9830 } 9831 9832 /*@ 9833 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 9834 9835 Collective 9836 9837 Input Parameters: 9838 + dm - The `DMPLEX` object 9839 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9840 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9841 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9842 9843 Level: intermediate 9844 9845 Notes: 9846 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 9847 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 9848 combination of other points' degrees of freedom. 9849 9850 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9851 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9852 9853 The reference counts of `anchorSection` and `anchorIS` are incremented. 9854 9855 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9856 @*/ 9857 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9858 { 9859 DM_Plex *plex = (DM_Plex *)dm->data; 9860 PetscMPIInt result; 9861 9862 PetscFunctionBegin; 9863 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9864 if (anchorSection) { 9865 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9866 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9867 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9868 } 9869 if (anchorIS) { 9870 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9871 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9872 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9873 } 9874 9875 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9876 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9877 plex->anchorSection = anchorSection; 9878 9879 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9880 PetscCall(ISDestroy(&plex->anchorIS)); 9881 plex->anchorIS = anchorIS; 9882 9883 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9884 PetscInt size, a, pStart, pEnd; 9885 const PetscInt *anchors; 9886 9887 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9888 PetscCall(ISGetLocalSize(anchorIS, &size)); 9889 PetscCall(ISGetIndices(anchorIS, &anchors)); 9890 for (a = 0; a < size; a++) { 9891 PetscInt p; 9892 9893 p = anchors[a]; 9894 if (p >= pStart && p < pEnd) { 9895 PetscInt dof; 9896 9897 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9898 if (dof) { 9899 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9900 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9901 } 9902 } 9903 } 9904 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9905 } 9906 /* reset the generic constraints */ 9907 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9908 PetscFunctionReturn(PETSC_SUCCESS); 9909 } 9910 9911 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9912 { 9913 PetscSection anchorSection; 9914 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9915 9916 PetscFunctionBegin; 9917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9918 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9919 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9920 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9921 if (numFields) { 9922 PetscInt f; 9923 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9924 9925 for (f = 0; f < numFields; f++) { 9926 PetscInt numComp; 9927 9928 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9929 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9930 } 9931 } 9932 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9933 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9934 pStart = PetscMax(pStart, sStart); 9935 pEnd = PetscMin(pEnd, sEnd); 9936 pEnd = PetscMax(pStart, pEnd); 9937 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9938 for (p = pStart; p < pEnd; p++) { 9939 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9940 if (dof) { 9941 PetscCall(PetscSectionGetDof(section, p, &dof)); 9942 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9943 for (f = 0; f < numFields; f++) { 9944 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9945 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9946 } 9947 } 9948 } 9949 PetscCall(PetscSectionSetUp(*cSec)); 9950 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9951 PetscFunctionReturn(PETSC_SUCCESS); 9952 } 9953 9954 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9955 { 9956 PetscSection aSec; 9957 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9958 const PetscInt *anchors; 9959 PetscInt numFields, f; 9960 IS aIS; 9961 MatType mtype; 9962 PetscBool iscuda, iskokkos; 9963 9964 PetscFunctionBegin; 9965 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9966 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9967 PetscCall(PetscSectionGetStorageSize(section, &n)); 9968 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9969 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9970 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9971 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9972 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9973 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9974 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9975 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9976 else mtype = MATSEQAIJ; 9977 PetscCall(MatSetType(*cMat, mtype)); 9978 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9979 PetscCall(ISGetIndices(aIS, &anchors)); 9980 /* cSec will be a subset of aSec and section */ 9981 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9982 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9983 PetscCall(PetscMalloc1(m + 1, &i)); 9984 i[0] = 0; 9985 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9986 for (p = pStart; p < pEnd; p++) { 9987 PetscInt rDof, rOff, r; 9988 9989 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9990 if (!rDof) continue; 9991 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9992 if (numFields) { 9993 for (f = 0; f < numFields; f++) { 9994 annz = 0; 9995 for (r = 0; r < rDof; r++) { 9996 a = anchors[rOff + r]; 9997 if (a < sStart || a >= sEnd) continue; 9998 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9999 annz += aDof; 10000 } 10001 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10002 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10003 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10004 } 10005 } else { 10006 annz = 0; 10007 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10008 for (q = 0; q < dof; q++) { 10009 a = anchors[rOff + q]; 10010 if (a < sStart || a >= sEnd) continue; 10011 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10012 annz += aDof; 10013 } 10014 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10015 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10016 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10017 } 10018 } 10019 nnz = i[m]; 10020 PetscCall(PetscMalloc1(nnz, &j)); 10021 offset = 0; 10022 for (p = pStart; p < pEnd; p++) { 10023 if (numFields) { 10024 for (f = 0; f < numFields; f++) { 10025 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10026 for (q = 0; q < dof; q++) { 10027 PetscInt rDof, rOff, r; 10028 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10029 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10030 for (r = 0; r < rDof; r++) { 10031 PetscInt s; 10032 10033 a = anchors[rOff + r]; 10034 if (a < sStart || a >= sEnd) continue; 10035 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10036 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10037 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10038 } 10039 } 10040 } 10041 } else { 10042 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10043 for (q = 0; q < dof; q++) { 10044 PetscInt rDof, rOff, r; 10045 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10046 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10047 for (r = 0; r < rDof; r++) { 10048 PetscInt s; 10049 10050 a = anchors[rOff + r]; 10051 if (a < sStart || a >= sEnd) continue; 10052 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10053 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10054 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10055 } 10056 } 10057 } 10058 } 10059 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10060 PetscCall(PetscFree(i)); 10061 PetscCall(PetscFree(j)); 10062 PetscCall(ISRestoreIndices(aIS, &anchors)); 10063 PetscFunctionReturn(PETSC_SUCCESS); 10064 } 10065 10066 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10067 { 10068 DM_Plex *plex = (DM_Plex *)dm->data; 10069 PetscSection anchorSection, section, cSec; 10070 Mat cMat; 10071 10072 PetscFunctionBegin; 10073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10074 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10075 if (anchorSection) { 10076 PetscInt Nf; 10077 10078 PetscCall(DMGetLocalSection(dm, §ion)); 10079 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10080 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10081 PetscCall(DMGetNumFields(dm, &Nf)); 10082 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10083 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10084 PetscCall(PetscSectionDestroy(&cSec)); 10085 PetscCall(MatDestroy(&cMat)); 10086 } 10087 PetscFunctionReturn(PETSC_SUCCESS); 10088 } 10089 10090 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10091 { 10092 IS subis; 10093 PetscSection section, subsection; 10094 10095 PetscFunctionBegin; 10096 PetscCall(DMGetLocalSection(dm, §ion)); 10097 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10098 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10099 /* Create subdomain */ 10100 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10101 /* Create submodel */ 10102 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10103 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10104 PetscCall(DMSetLocalSection(*subdm, subsection)); 10105 PetscCall(PetscSectionDestroy(&subsection)); 10106 PetscCall(DMCopyDisc(dm, *subdm)); 10107 /* Create map from submodel to global model */ 10108 if (is) { 10109 PetscSection sectionGlobal, subsectionGlobal; 10110 IS spIS; 10111 const PetscInt *spmap; 10112 PetscInt *subIndices; 10113 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10114 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10115 10116 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10117 PetscCall(ISGetIndices(spIS, &spmap)); 10118 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10119 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10120 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10121 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10122 for (p = pStart; p < pEnd; ++p) { 10123 PetscInt gdof, pSubSize = 0; 10124 10125 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10126 if (gdof > 0) { 10127 for (f = 0; f < Nf; ++f) { 10128 PetscInt fdof, fcdof; 10129 10130 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10131 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10132 pSubSize += fdof - fcdof; 10133 } 10134 subSize += pSubSize; 10135 if (pSubSize) { 10136 if (bs < 0) { 10137 bs = pSubSize; 10138 } else if (bs != pSubSize) { 10139 /* Layout does not admit a pointwise block size */ 10140 bs = 1; 10141 } 10142 } 10143 } 10144 } 10145 /* Must have same blocksize on all procs (some might have no points) */ 10146 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10147 bsLocal[1] = bs; 10148 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10149 if (bsMinMax[0] != bsMinMax[1]) { 10150 bs = 1; 10151 } else { 10152 bs = bsMinMax[0]; 10153 } 10154 PetscCall(PetscMalloc1(subSize, &subIndices)); 10155 for (p = pStart; p < pEnd; ++p) { 10156 PetscInt gdof, goff; 10157 10158 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10159 if (gdof > 0) { 10160 const PetscInt point = spmap[p]; 10161 10162 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10163 for (f = 0; f < Nf; ++f) { 10164 PetscInt fdof, fcdof, fc, f2, poff = 0; 10165 10166 /* Can get rid of this loop by storing field information in the global section */ 10167 for (f2 = 0; f2 < f; ++f2) { 10168 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10169 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10170 poff += fdof - fcdof; 10171 } 10172 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10173 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10174 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10175 } 10176 } 10177 } 10178 PetscCall(ISRestoreIndices(spIS, &spmap)); 10179 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10180 if (bs > 1) { 10181 /* We need to check that the block size does not come from non-contiguous fields */ 10182 PetscInt i, j, set = 1; 10183 for (i = 0; i < subSize; i += bs) { 10184 for (j = 0; j < bs; ++j) { 10185 if (subIndices[i + j] != subIndices[i] + j) { 10186 set = 0; 10187 break; 10188 } 10189 } 10190 } 10191 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10192 } 10193 /* Attach nullspace */ 10194 for (f = 0; f < Nf; ++f) { 10195 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10196 if ((*subdm)->nullspaceConstructors[f]) break; 10197 } 10198 if (f < Nf) { 10199 MatNullSpace nullSpace; 10200 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10201 10202 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10203 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10204 } 10205 } 10206 PetscFunctionReturn(PETSC_SUCCESS); 10207 } 10208 10209 /*@ 10210 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10211 10212 Input Parameters: 10213 + dm - The `DM` 10214 - dummy - unused argument 10215 10216 Options Database Key: 10217 . -dm_plex_monitor_throughput - Activate the monitor 10218 10219 Level: developer 10220 10221 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10222 @*/ 10223 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10224 { 10225 PetscLogHandler default_handler; 10226 10227 PetscFunctionBegin; 10228 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10229 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10230 if (default_handler) { 10231 PetscLogEvent event; 10232 PetscEventPerfInfo eventInfo; 10233 PetscReal cellRate, flopRate; 10234 PetscInt cStart, cEnd, Nf, N; 10235 const char *name; 10236 10237 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10238 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10239 PetscCall(DMGetNumFields(dm, &Nf)); 10240 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10241 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10242 N = (cEnd - cStart) * Nf * eventInfo.count; 10243 flopRate = eventInfo.flops / eventInfo.time; 10244 cellRate = N / eventInfo.time; 10245 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))); 10246 } else { 10247 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off or the default log handler is not running. Reconfigure using --with-log and run with -log_view."); 10248 } 10249 PetscFunctionReturn(PETSC_SUCCESS); 10250 } 10251