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, "DMPlexGetUseCeed_C", NULL)); 2542 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2543 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2544 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2545 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2546 PetscCall(PetscFree(mesh->cones)); 2547 PetscCall(PetscFree(mesh->coneOrientations)); 2548 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2549 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2550 PetscCall(PetscFree(mesh->supports)); 2551 PetscCall(PetscFree(mesh->cellTypes)); 2552 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2553 PetscCall(PetscFree(mesh->tetgenOpts)); 2554 PetscCall(PetscFree(mesh->triangleOpts)); 2555 PetscCall(PetscFree(mesh->transformType)); 2556 PetscCall(PetscFree(mesh->distributionName)); 2557 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2558 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2559 PetscCall(ISDestroy(&mesh->subpointIS)); 2560 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2561 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2562 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2563 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2564 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2565 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2566 PetscCall(ISDestroy(&mesh->anchorIS)); 2567 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2568 PetscCall(PetscFree(mesh->parents)); 2569 PetscCall(PetscFree(mesh->childIDs)); 2570 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2571 PetscCall(PetscFree(mesh->children)); 2572 PetscCall(DMDestroy(&mesh->referenceTree)); 2573 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2574 PetscCall(PetscFree(mesh->neighbors)); 2575 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2576 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2577 PetscCall(PetscFree(mesh)); 2578 PetscFunctionReturn(PETSC_SUCCESS); 2579 } 2580 2581 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2582 { 2583 PetscSection sectionGlobal; 2584 PetscInt bs = -1, mbs; 2585 PetscInt localSize, localStart = 0; 2586 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2587 MatType mtype; 2588 ISLocalToGlobalMapping ltog; 2589 2590 PetscFunctionBegin; 2591 PetscCall(MatInitializePackage()); 2592 mtype = dm->mattype; 2593 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2594 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2595 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2596 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2597 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2598 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2599 PetscCall(MatSetType(*J, mtype)); 2600 PetscCall(MatSetFromOptions(*J)); 2601 PetscCall(MatGetBlockSize(*J, &mbs)); 2602 if (mbs > 1) bs = mbs; 2603 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2604 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2605 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2606 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2607 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2608 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2609 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2610 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2611 if (!isShell) { 2612 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2613 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2614 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2615 2616 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2617 2618 PetscCall(PetscCalloc1(localSize, &pblocks)); 2619 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2620 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2621 for (p = pStart; p < pEnd; ++p) { 2622 switch (dm->blocking_type) { 2623 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2624 PetscInt bdof, offset; 2625 2626 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2627 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2628 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2629 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2630 dof = dof < 0 ? -(dof + 1) : dof; 2631 bdof = cdof && (dof - cdof) ? 1 : dof; 2632 if (dof) { 2633 if (bs < 0) { 2634 bs = bdof; 2635 } else if (bs != bdof) { 2636 bs = 1; 2637 } 2638 } 2639 } break; 2640 case DM_BLOCKING_FIELD_NODE: { 2641 for (PetscInt field = 0; field < num_fields; field++) { 2642 PetscInt num_comp, bdof, offset; 2643 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2644 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2645 if (dof < 0) continue; 2646 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2647 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2648 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); 2649 PetscInt num_nodes = dof / num_comp; 2650 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2651 // Handle possibly constant block size (unlikely) 2652 bdof = cdof && (dof - cdof) ? 1 : dof; 2653 if (dof) { 2654 if (bs < 0) { 2655 bs = bdof; 2656 } else if (bs != bdof) { 2657 bs = 1; 2658 } 2659 } 2660 } 2661 } break; 2662 } 2663 } 2664 /* Must have same blocksize on all procs (some might have no points) */ 2665 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2666 bsLocal[1] = bs; 2667 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2668 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2669 else bs = bsMinMax[0]; 2670 bs = PetscMax(1, bs); 2671 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2672 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2673 PetscCall(MatSetBlockSize(*J, bs)); 2674 PetscCall(MatSetUp(*J)); 2675 } else { 2676 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2677 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2678 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2679 } 2680 { // Consolidate blocks 2681 PetscInt nblocks = 0; 2682 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2683 if (pblocks[i] == 0) continue; 2684 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2685 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]); 2686 } 2687 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2688 } 2689 PetscCall(PetscFree(pblocks)); 2690 } 2691 PetscCall(MatSetDM(*J, dm)); 2692 PetscFunctionReturn(PETSC_SUCCESS); 2693 } 2694 2695 /*@ 2696 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2697 2698 Not Collective 2699 2700 Input Parameter: 2701 . dm - The `DMPLEX` 2702 2703 Output Parameter: 2704 . subsection - The subdomain section 2705 2706 Level: developer 2707 2708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2709 @*/ 2710 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2711 { 2712 DM_Plex *mesh = (DM_Plex *)dm->data; 2713 2714 PetscFunctionBegin; 2715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2716 if (!mesh->subdomainSection) { 2717 PetscSection section; 2718 PetscSF sf; 2719 2720 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2721 PetscCall(DMGetLocalSection(dm, §ion)); 2722 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2723 PetscCall(PetscSFDestroy(&sf)); 2724 } 2725 *subsection = mesh->subdomainSection; 2726 PetscFunctionReturn(PETSC_SUCCESS); 2727 } 2728 2729 /*@ 2730 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2731 2732 Not Collective 2733 2734 Input Parameter: 2735 . dm - The `DMPLEX` 2736 2737 Output Parameters: 2738 + pStart - The first mesh point 2739 - pEnd - The upper bound for mesh points 2740 2741 Level: beginner 2742 2743 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2744 @*/ 2745 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2746 { 2747 DM_Plex *mesh = (DM_Plex *)dm->data; 2748 2749 PetscFunctionBegin; 2750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2751 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2752 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2753 PetscFunctionReturn(PETSC_SUCCESS); 2754 } 2755 2756 /*@ 2757 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2758 2759 Not Collective 2760 2761 Input Parameters: 2762 + dm - The `DMPLEX` 2763 . pStart - The first mesh point 2764 - pEnd - The upper bound for mesh points 2765 2766 Level: beginner 2767 2768 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2769 @*/ 2770 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2771 { 2772 DM_Plex *mesh = (DM_Plex *)dm->data; 2773 2774 PetscFunctionBegin; 2775 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2776 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2777 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2778 PetscCall(PetscFree(mesh->cellTypes)); 2779 PetscFunctionReturn(PETSC_SUCCESS); 2780 } 2781 2782 /*@ 2783 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2784 2785 Not Collective 2786 2787 Input Parameters: 2788 + dm - The `DMPLEX` 2789 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2790 2791 Output Parameter: 2792 . size - The cone size for point `p` 2793 2794 Level: beginner 2795 2796 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2797 @*/ 2798 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2799 { 2800 DM_Plex *mesh = (DM_Plex *)dm->data; 2801 2802 PetscFunctionBegin; 2803 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2804 PetscAssertPointer(size, 3); 2805 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2806 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2807 PetscFunctionReturn(PETSC_SUCCESS); 2808 } 2809 2810 /*@ 2811 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2812 2813 Not Collective 2814 2815 Input Parameters: 2816 + dm - The `DMPLEX` 2817 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2818 - size - The cone size for point `p` 2819 2820 Level: beginner 2821 2822 Note: 2823 This should be called after `DMPlexSetChart()`. 2824 2825 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2826 @*/ 2827 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2828 { 2829 DM_Plex *mesh = (DM_Plex *)dm->data; 2830 2831 PetscFunctionBegin; 2832 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2833 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2834 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2835 PetscFunctionReturn(PETSC_SUCCESS); 2836 } 2837 2838 /*@C 2839 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2840 2841 Not Collective 2842 2843 Input Parameters: 2844 + dm - The `DMPLEX` 2845 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2846 2847 Output Parameter: 2848 . cone - An array of points which are on the in-edges for point `p` 2849 2850 Level: beginner 2851 2852 Fortran Notes: 2853 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2854 `DMPlexRestoreCone()` is not needed/available in C. 2855 2856 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 2857 @*/ 2858 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2859 { 2860 DM_Plex *mesh = (DM_Plex *)dm->data; 2861 PetscInt off; 2862 2863 PetscFunctionBegin; 2864 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2865 PetscAssertPointer(cone, 3); 2866 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2867 *cone = &mesh->cones[off]; 2868 PetscFunctionReturn(PETSC_SUCCESS); 2869 } 2870 2871 /*@C 2872 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2873 2874 Not Collective 2875 2876 Input Parameters: 2877 + dm - The `DMPLEX` 2878 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2879 2880 Output Parameters: 2881 + pConesSection - `PetscSection` describing the layout of `pCones` 2882 - pCones - An array of points which are on the in-edges for the point set `p` 2883 2884 Level: intermediate 2885 2886 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 2887 @*/ 2888 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2889 { 2890 PetscSection cs, newcs; 2891 PetscInt *cones; 2892 PetscInt *newarr = NULL; 2893 PetscInt n; 2894 2895 PetscFunctionBegin; 2896 PetscCall(DMPlexGetCones(dm, &cones)); 2897 PetscCall(DMPlexGetConeSection(dm, &cs)); 2898 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2899 if (pConesSection) *pConesSection = newcs; 2900 if (pCones) { 2901 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2902 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2903 } 2904 PetscFunctionReturn(PETSC_SUCCESS); 2905 } 2906 2907 /*@ 2908 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2909 2910 Not Collective 2911 2912 Input Parameters: 2913 + dm - The `DMPLEX` 2914 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2915 2916 Output Parameter: 2917 . expandedPoints - An array of vertices recursively expanded from input points 2918 2919 Level: advanced 2920 2921 Notes: 2922 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 2923 2924 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 2925 2926 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 2927 `DMPlexGetDepth()`, `IS` 2928 @*/ 2929 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2930 { 2931 IS *expandedPointsAll; 2932 PetscInt depth; 2933 2934 PetscFunctionBegin; 2935 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2936 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2937 PetscAssertPointer(expandedPoints, 3); 2938 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2939 *expandedPoints = expandedPointsAll[0]; 2940 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2941 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2942 PetscFunctionReturn(PETSC_SUCCESS); 2943 } 2944 2945 /*@ 2946 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). 2947 2948 Not Collective 2949 2950 Input Parameters: 2951 + dm - The `DMPLEX` 2952 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2953 2954 Output Parameters: 2955 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 2956 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2957 - sections - (optional) An array of sections which describe mappings from points to their cone points 2958 2959 Level: advanced 2960 2961 Notes: 2962 Like `DMPlexGetConeTuple()` but recursive. 2963 2964 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. 2965 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2966 2967 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\: 2968 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 2969 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 2970 2971 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 2972 `DMPlexGetDepth()`, `PetscSection`, `IS` 2973 @*/ 2974 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2975 { 2976 const PetscInt *arr0 = NULL, *cone = NULL; 2977 PetscInt *arr = NULL, *newarr = NULL; 2978 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2979 IS *expandedPoints_; 2980 PetscSection *sections_; 2981 2982 PetscFunctionBegin; 2983 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2984 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2985 if (depth) PetscAssertPointer(depth, 3); 2986 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 2987 if (sections) PetscAssertPointer(sections, 5); 2988 PetscCall(ISGetLocalSize(points, &n)); 2989 PetscCall(ISGetIndices(points, &arr0)); 2990 PetscCall(DMPlexGetDepth(dm, &depth_)); 2991 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2992 PetscCall(PetscCalloc1(depth_, §ions_)); 2993 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2994 for (d = depth_ - 1; d >= 0; d--) { 2995 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2996 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2997 for (i = 0; i < n; i++) { 2998 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2999 if (arr[i] >= start && arr[i] < end) { 3000 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3001 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3002 } else { 3003 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3004 } 3005 } 3006 PetscCall(PetscSectionSetUp(sections_[d])); 3007 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3008 PetscCall(PetscMalloc1(newn, &newarr)); 3009 for (i = 0; i < n; i++) { 3010 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3011 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3012 if (cn > 1) { 3013 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3014 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3015 } else { 3016 newarr[co] = arr[i]; 3017 } 3018 } 3019 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3020 arr = newarr; 3021 n = newn; 3022 } 3023 PetscCall(ISRestoreIndices(points, &arr0)); 3024 *depth = depth_; 3025 if (expandedPoints) *expandedPoints = expandedPoints_; 3026 else { 3027 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3028 PetscCall(PetscFree(expandedPoints_)); 3029 } 3030 if (sections) *sections = sections_; 3031 else { 3032 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3033 PetscCall(PetscFree(sections_)); 3034 } 3035 PetscFunctionReturn(PETSC_SUCCESS); 3036 } 3037 3038 /*@ 3039 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3040 3041 Not Collective 3042 3043 Input Parameters: 3044 + dm - The `DMPLEX` 3045 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3046 3047 Output Parameters: 3048 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3049 . expandedPoints - (optional) An array of recursively expanded cones 3050 - sections - (optional) An array of sections which describe mappings from points to their cone points 3051 3052 Level: advanced 3053 3054 Note: 3055 See `DMPlexGetConeRecursive()` 3056 3057 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3058 `DMPlexGetDepth()`, `IS`, `PetscSection` 3059 @*/ 3060 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3061 { 3062 PetscInt d, depth_; 3063 3064 PetscFunctionBegin; 3065 PetscCall(DMPlexGetDepth(dm, &depth_)); 3066 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3067 if (depth) *depth = 0; 3068 if (expandedPoints) { 3069 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3070 PetscCall(PetscFree(*expandedPoints)); 3071 } 3072 if (sections) { 3073 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3074 PetscCall(PetscFree(*sections)); 3075 } 3076 PetscFunctionReturn(PETSC_SUCCESS); 3077 } 3078 3079 /*@ 3080 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 3081 3082 Not Collective 3083 3084 Input Parameters: 3085 + dm - The `DMPLEX` 3086 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3087 - cone - An array of points which are on the in-edges for point `p` 3088 3089 Level: beginner 3090 3091 Note: 3092 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3093 3094 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3095 @*/ 3096 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3097 { 3098 DM_Plex *mesh = (DM_Plex *)dm->data; 3099 PetscInt dof, off, c; 3100 3101 PetscFunctionBegin; 3102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3103 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3104 if (dof) PetscAssertPointer(cone, 3); 3105 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3106 if (PetscDefined(USE_DEBUG)) { 3107 PetscInt pStart, pEnd; 3108 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3109 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); 3110 for (c = 0; c < dof; ++c) { 3111 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); 3112 mesh->cones[off + c] = cone[c]; 3113 } 3114 } else { 3115 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3116 } 3117 PetscFunctionReturn(PETSC_SUCCESS); 3118 } 3119 3120 /*@C 3121 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3122 3123 Not Collective 3124 3125 Input Parameters: 3126 + dm - The `DMPLEX` 3127 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3128 3129 Output Parameter: 3130 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3131 integer giving the prescription for cone traversal. 3132 3133 Level: beginner 3134 3135 Note: 3136 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3137 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3138 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3139 with the identity. 3140 3141 Fortran Notes: 3142 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3143 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3144 3145 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3146 @*/ 3147 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3148 { 3149 DM_Plex *mesh = (DM_Plex *)dm->data; 3150 PetscInt off; 3151 3152 PetscFunctionBegin; 3153 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3154 if (PetscDefined(USE_DEBUG)) { 3155 PetscInt dof; 3156 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3157 if (dof) PetscAssertPointer(coneOrientation, 3); 3158 } 3159 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3160 3161 *coneOrientation = &mesh->coneOrientations[off]; 3162 PetscFunctionReturn(PETSC_SUCCESS); 3163 } 3164 3165 /*@ 3166 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3167 3168 Not Collective 3169 3170 Input Parameters: 3171 + dm - The `DMPLEX` 3172 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3173 - coneOrientation - An array of orientations 3174 3175 Level: beginner 3176 3177 Notes: 3178 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3179 3180 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3181 3182 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3183 @*/ 3184 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3185 { 3186 DM_Plex *mesh = (DM_Plex *)dm->data; 3187 PetscInt pStart, pEnd; 3188 PetscInt dof, off, c; 3189 3190 PetscFunctionBegin; 3191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3192 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3193 if (dof) PetscAssertPointer(coneOrientation, 3); 3194 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3195 if (PetscDefined(USE_DEBUG)) { 3196 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3197 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); 3198 for (c = 0; c < dof; ++c) { 3199 PetscInt cdof, o = coneOrientation[c]; 3200 3201 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3202 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); 3203 mesh->coneOrientations[off + c] = o; 3204 } 3205 } else { 3206 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3207 } 3208 PetscFunctionReturn(PETSC_SUCCESS); 3209 } 3210 3211 /*@ 3212 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3213 3214 Not Collective 3215 3216 Input Parameters: 3217 + dm - The `DMPLEX` 3218 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3219 . conePos - The local index in the cone where the point should be put 3220 - conePoint - The mesh point to insert 3221 3222 Level: beginner 3223 3224 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3225 @*/ 3226 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3227 { 3228 DM_Plex *mesh = (DM_Plex *)dm->data; 3229 PetscInt pStart, pEnd; 3230 PetscInt dof, off; 3231 3232 PetscFunctionBegin; 3233 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3234 if (PetscDefined(USE_DEBUG)) { 3235 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3236 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); 3237 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); 3238 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3239 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); 3240 } 3241 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3242 mesh->cones[off + conePos] = conePoint; 3243 PetscFunctionReturn(PETSC_SUCCESS); 3244 } 3245 3246 /*@ 3247 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3248 3249 Not Collective 3250 3251 Input Parameters: 3252 + dm - The `DMPLEX` 3253 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3254 . conePos - The local index in the cone where the point should be put 3255 - coneOrientation - The point orientation to insert 3256 3257 Level: beginner 3258 3259 Note: 3260 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3261 3262 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3263 @*/ 3264 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3265 { 3266 DM_Plex *mesh = (DM_Plex *)dm->data; 3267 PetscInt pStart, pEnd; 3268 PetscInt dof, off; 3269 3270 PetscFunctionBegin; 3271 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3272 if (PetscDefined(USE_DEBUG)) { 3273 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3274 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); 3275 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3276 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); 3277 } 3278 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3279 mesh->coneOrientations[off + conePos] = coneOrientation; 3280 PetscFunctionReturn(PETSC_SUCCESS); 3281 } 3282 3283 /*@C 3284 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3285 3286 Not collective 3287 3288 Input Parameters: 3289 + dm - The DMPlex 3290 - p - The point, which must lie in the chart set with DMPlexSetChart() 3291 3292 Output Parameters: 3293 + cone - An array of points which are on the in-edges for point `p` 3294 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3295 integer giving the prescription for cone traversal. 3296 3297 Level: beginner 3298 3299 Notes: 3300 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3301 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3302 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3303 with the identity. 3304 3305 Fortran Notes: 3306 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3307 `DMPlexRestoreCone()` is not needed/available in C. 3308 3309 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3310 @*/ 3311 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3312 { 3313 DM_Plex *mesh = (DM_Plex *)dm->data; 3314 3315 PetscFunctionBegin; 3316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3317 if (mesh->tr) { 3318 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3319 } else { 3320 PetscInt off; 3321 if (PetscDefined(USE_DEBUG)) { 3322 PetscInt dof; 3323 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3324 if (dof) { 3325 if (cone) PetscAssertPointer(cone, 3); 3326 if (ornt) PetscAssertPointer(ornt, 4); 3327 } 3328 } 3329 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3330 if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB 3331 if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL; 3332 } 3333 PetscFunctionReturn(PETSC_SUCCESS); 3334 } 3335 3336 /*@C 3337 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3338 3339 Not Collective 3340 3341 Input Parameters: 3342 + dm - The DMPlex 3343 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3344 . cone - An array of points which are on the in-edges for point p 3345 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3346 integer giving the prescription for cone traversal. 3347 3348 Level: beginner 3349 3350 Notes: 3351 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3352 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3353 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3354 with the identity. 3355 3356 Fortran Notes: 3357 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3358 `DMPlexRestoreCone()` is not needed/available in C. 3359 3360 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3361 @*/ 3362 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3363 { 3364 DM_Plex *mesh = (DM_Plex *)dm->data; 3365 3366 PetscFunctionBegin; 3367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3368 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3369 PetscFunctionReturn(PETSC_SUCCESS); 3370 } 3371 3372 /*@ 3373 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3374 3375 Not Collective 3376 3377 Input Parameters: 3378 + dm - The `DMPLEX` 3379 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3380 3381 Output Parameter: 3382 . size - The support size for point `p` 3383 3384 Level: beginner 3385 3386 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3387 @*/ 3388 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3389 { 3390 DM_Plex *mesh = (DM_Plex *)dm->data; 3391 3392 PetscFunctionBegin; 3393 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3394 PetscAssertPointer(size, 3); 3395 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3396 PetscFunctionReturn(PETSC_SUCCESS); 3397 } 3398 3399 /*@ 3400 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3401 3402 Not Collective 3403 3404 Input Parameters: 3405 + dm - The `DMPLEX` 3406 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3407 - size - The support size for point `p` 3408 3409 Level: beginner 3410 3411 Note: 3412 This should be called after `DMPlexSetChart()`. 3413 3414 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3415 @*/ 3416 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3417 { 3418 DM_Plex *mesh = (DM_Plex *)dm->data; 3419 3420 PetscFunctionBegin; 3421 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3422 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3423 PetscFunctionReturn(PETSC_SUCCESS); 3424 } 3425 3426 /*@C 3427 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3428 3429 Not Collective 3430 3431 Input Parameters: 3432 + dm - The `DMPLEX` 3433 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3434 3435 Output Parameter: 3436 . support - An array of points which are on the out-edges for point `p` 3437 3438 Level: beginner 3439 3440 Fortran Notes: 3441 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3442 `DMPlexRestoreSupport()` is not needed/available in C. 3443 3444 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3445 @*/ 3446 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3447 { 3448 DM_Plex *mesh = (DM_Plex *)dm->data; 3449 PetscInt off; 3450 3451 PetscFunctionBegin; 3452 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3453 PetscAssertPointer(support, 3); 3454 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3455 *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB 3456 PetscFunctionReturn(PETSC_SUCCESS); 3457 } 3458 3459 /*@ 3460 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3461 3462 Not Collective 3463 3464 Input Parameters: 3465 + dm - The `DMPLEX` 3466 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3467 - support - An array of points which are on the out-edges for point `p` 3468 3469 Level: beginner 3470 3471 Note: 3472 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3473 3474 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3475 @*/ 3476 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3477 { 3478 DM_Plex *mesh = (DM_Plex *)dm->data; 3479 PetscInt pStart, pEnd; 3480 PetscInt dof, off, c; 3481 3482 PetscFunctionBegin; 3483 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3484 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3485 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3486 if (dof) PetscAssertPointer(support, 3); 3487 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3488 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); 3489 for (c = 0; c < dof; ++c) { 3490 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); 3491 mesh->supports[off + c] = support[c]; 3492 } 3493 PetscFunctionReturn(PETSC_SUCCESS); 3494 } 3495 3496 /*@ 3497 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3498 3499 Not Collective 3500 3501 Input Parameters: 3502 + dm - The `DMPLEX` 3503 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3504 . supportPos - The local index in the cone where the point should be put 3505 - supportPoint - The mesh point to insert 3506 3507 Level: beginner 3508 3509 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3510 @*/ 3511 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3512 { 3513 DM_Plex *mesh = (DM_Plex *)dm->data; 3514 PetscInt pStart, pEnd; 3515 PetscInt dof, off; 3516 3517 PetscFunctionBegin; 3518 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3519 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3520 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3521 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3522 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); 3523 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); 3524 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); 3525 mesh->supports[off + supportPos] = supportPoint; 3526 PetscFunctionReturn(PETSC_SUCCESS); 3527 } 3528 3529 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3530 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3531 { 3532 switch (ct) { 3533 case DM_POLYTOPE_SEGMENT: 3534 if (o == -1) return -2; 3535 break; 3536 case DM_POLYTOPE_TRIANGLE: 3537 if (o == -3) return -1; 3538 if (o == -2) return -3; 3539 if (o == -1) return -2; 3540 break; 3541 case DM_POLYTOPE_QUADRILATERAL: 3542 if (o == -4) return -2; 3543 if (o == -3) return -1; 3544 if (o == -2) return -4; 3545 if (o == -1) return -3; 3546 break; 3547 default: 3548 return o; 3549 } 3550 return o; 3551 } 3552 3553 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3554 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3555 { 3556 switch (ct) { 3557 case DM_POLYTOPE_SEGMENT: 3558 if ((o == -2) || (o == 1)) return -1; 3559 if (o == -1) return 0; 3560 break; 3561 case DM_POLYTOPE_TRIANGLE: 3562 if (o == -3) return -2; 3563 if (o == -2) return -1; 3564 if (o == -1) return -3; 3565 break; 3566 case DM_POLYTOPE_QUADRILATERAL: 3567 if (o == -4) return -2; 3568 if (o == -3) return -1; 3569 if (o == -2) return -4; 3570 if (o == -1) return -3; 3571 break; 3572 default: 3573 return o; 3574 } 3575 return o; 3576 } 3577 3578 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3579 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3580 { 3581 PetscInt pStart, pEnd, p; 3582 3583 PetscFunctionBegin; 3584 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3585 for (p = pStart; p < pEnd; ++p) { 3586 const PetscInt *cone, *ornt; 3587 PetscInt coneSize, c; 3588 3589 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3590 PetscCall(DMPlexGetCone(dm, p, &cone)); 3591 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3592 for (c = 0; c < coneSize; ++c) { 3593 DMPolytopeType ct; 3594 const PetscInt o = ornt[c]; 3595 3596 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3597 switch (ct) { 3598 case DM_POLYTOPE_SEGMENT: 3599 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3600 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3601 break; 3602 case DM_POLYTOPE_TRIANGLE: 3603 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3604 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3605 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3606 break; 3607 case DM_POLYTOPE_QUADRILATERAL: 3608 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3609 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3610 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3611 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3612 break; 3613 default: 3614 break; 3615 } 3616 } 3617 } 3618 PetscFunctionReturn(PETSC_SUCCESS); 3619 } 3620 3621 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3622 { 3623 DM_Plex *mesh = (DM_Plex *)dm->data; 3624 3625 PetscFunctionBeginHot; 3626 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3627 if (useCone) { 3628 PetscCall(DMPlexGetConeSize(dm, p, size)); 3629 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3630 } else { 3631 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3632 PetscCall(DMPlexGetSupport(dm, p, arr)); 3633 } 3634 } else { 3635 if (useCone) { 3636 const PetscSection s = mesh->coneSection; 3637 const PetscInt ps = p - s->pStart; 3638 const PetscInt off = s->atlasOff[ps]; 3639 3640 *size = s->atlasDof[ps]; 3641 *arr = mesh->cones + off; 3642 *ornt = mesh->coneOrientations + off; 3643 } else { 3644 const PetscSection s = mesh->supportSection; 3645 const PetscInt ps = p - s->pStart; 3646 const PetscInt off = s->atlasOff[ps]; 3647 3648 *size = s->atlasDof[ps]; 3649 *arr = mesh->supports + off; 3650 } 3651 } 3652 PetscFunctionReturn(PETSC_SUCCESS); 3653 } 3654 3655 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3656 { 3657 DM_Plex *mesh = (DM_Plex *)dm->data; 3658 3659 PetscFunctionBeginHot; 3660 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3661 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3662 } 3663 PetscFunctionReturn(PETSC_SUCCESS); 3664 } 3665 3666 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3667 { 3668 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3669 PetscInt *closure; 3670 const PetscInt *tmp = NULL, *tmpO = NULL; 3671 PetscInt off = 0, tmpSize, t; 3672 3673 PetscFunctionBeginHot; 3674 if (ornt) { 3675 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3676 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3677 } 3678 if (*points) { 3679 closure = *points; 3680 } else { 3681 PetscInt maxConeSize, maxSupportSize; 3682 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3683 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3684 } 3685 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3686 if (ct == DM_POLYTOPE_UNKNOWN) { 3687 closure[off++] = p; 3688 closure[off++] = 0; 3689 for (t = 0; t < tmpSize; ++t) { 3690 closure[off++] = tmp[t]; 3691 closure[off++] = tmpO ? tmpO[t] : 0; 3692 } 3693 } else { 3694 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3695 3696 /* We assume that cells with a valid type have faces with a valid type */ 3697 closure[off++] = p; 3698 closure[off++] = ornt; 3699 for (t = 0; t < tmpSize; ++t) { 3700 DMPolytopeType ft; 3701 3702 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3703 closure[off++] = tmp[arr[t]]; 3704 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3705 } 3706 } 3707 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3708 if (numPoints) *numPoints = tmpSize + 1; 3709 if (points) *points = closure; 3710 PetscFunctionReturn(PETSC_SUCCESS); 3711 } 3712 3713 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3714 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3715 { 3716 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3717 const PetscInt *cone, *ornt; 3718 PetscInt *pts, *closure = NULL; 3719 DMPolytopeType ft; 3720 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3721 PetscInt dim, coneSize, c, d, clSize, cl; 3722 3723 PetscFunctionBeginHot; 3724 PetscCall(DMGetDimension(dm, &dim)); 3725 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3726 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3727 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3728 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3729 maxSize = PetscMax(coneSeries, supportSeries); 3730 if (*points) { 3731 pts = *points; 3732 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3733 c = 0; 3734 pts[c++] = point; 3735 pts[c++] = o; 3736 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3737 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3738 for (cl = 0; cl < clSize * 2; cl += 2) { 3739 pts[c++] = closure[cl]; 3740 pts[c++] = closure[cl + 1]; 3741 } 3742 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3743 for (cl = 0; cl < clSize * 2; cl += 2) { 3744 pts[c++] = closure[cl]; 3745 pts[c++] = closure[cl + 1]; 3746 } 3747 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3748 for (d = 2; d < coneSize; ++d) { 3749 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3750 pts[c++] = cone[arr[d * 2 + 0]]; 3751 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3752 } 3753 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3754 if (dim >= 3) { 3755 for (d = 2; d < coneSize; ++d) { 3756 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3757 const PetscInt *fcone, *fornt; 3758 PetscInt fconeSize, fc, i; 3759 3760 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3761 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3762 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3763 for (fc = 0; fc < fconeSize; ++fc) { 3764 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3765 const PetscInt co = farr[fc * 2 + 1]; 3766 3767 for (i = 0; i < c; i += 2) 3768 if (pts[i] == cp) break; 3769 if (i == c) { 3770 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3771 pts[c++] = cp; 3772 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3773 } 3774 } 3775 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3776 } 3777 } 3778 *numPoints = c / 2; 3779 *points = pts; 3780 PetscFunctionReturn(PETSC_SUCCESS); 3781 } 3782 3783 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3784 { 3785 DMPolytopeType ct; 3786 PetscInt *closure, *fifo; 3787 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3788 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3789 PetscInt depth, maxSize; 3790 3791 PetscFunctionBeginHot; 3792 PetscCall(DMPlexGetDepth(dm, &depth)); 3793 if (depth == 1) { 3794 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3795 PetscFunctionReturn(PETSC_SUCCESS); 3796 } 3797 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3798 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3799 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3800 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3801 PetscFunctionReturn(PETSC_SUCCESS); 3802 } 3803 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3804 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3805 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3806 maxSize = PetscMax(coneSeries, supportSeries); 3807 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3808 if (*points) { 3809 closure = *points; 3810 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3811 closure[closureSize++] = p; 3812 closure[closureSize++] = ornt; 3813 fifo[fifoSize++] = p; 3814 fifo[fifoSize++] = ornt; 3815 fifo[fifoSize++] = ct; 3816 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3817 while (fifoSize - fifoStart) { 3818 const PetscInt q = fifo[fifoStart++]; 3819 const PetscInt o = fifo[fifoStart++]; 3820 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3821 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3822 const PetscInt *tmp, *tmpO = NULL; 3823 PetscInt tmpSize, t; 3824 3825 if (PetscDefined(USE_DEBUG)) { 3826 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3827 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); 3828 } 3829 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3830 for (t = 0; t < tmpSize; ++t) { 3831 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3832 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3833 const PetscInt cp = tmp[ip]; 3834 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3835 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3836 PetscInt c; 3837 3838 /* Check for duplicate */ 3839 for (c = 0; c < closureSize; c += 2) { 3840 if (closure[c] == cp) break; 3841 } 3842 if (c == closureSize) { 3843 closure[closureSize++] = cp; 3844 closure[closureSize++] = co; 3845 fifo[fifoSize++] = cp; 3846 fifo[fifoSize++] = co; 3847 fifo[fifoSize++] = ct; 3848 } 3849 } 3850 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3851 } 3852 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3853 if (numPoints) *numPoints = closureSize / 2; 3854 if (points) *points = closure; 3855 PetscFunctionReturn(PETSC_SUCCESS); 3856 } 3857 3858 /*@C 3859 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3860 3861 Not Collective 3862 3863 Input Parameters: 3864 + dm - The `DMPLEX` 3865 . p - The mesh point 3866 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 3867 3868 Input/Output Parameter: 3869 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3870 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 3871 3872 Output Parameter: 3873 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 3874 3875 Level: beginner 3876 3877 Note: 3878 If using internal storage (points is `NULL` on input), each call overwrites the last output. 3879 3880 Fortran Notes: 3881 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 3882 3883 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3884 @*/ 3885 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3886 { 3887 PetscFunctionBeginHot; 3888 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3889 if (numPoints) PetscAssertPointer(numPoints, 4); 3890 if (points) PetscAssertPointer(points, 5); 3891 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3892 PetscFunctionReturn(PETSC_SUCCESS); 3893 } 3894 3895 /*@C 3896 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3897 3898 Not Collective 3899 3900 Input Parameters: 3901 + dm - The `DMPLEX` 3902 . p - The mesh point 3903 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 3904 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 3905 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3906 3907 Level: beginner 3908 3909 Note: 3910 If not using internal storage (points is not `NULL` on input), this call is unnecessary 3911 3912 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3913 @*/ 3914 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3915 { 3916 PetscFunctionBeginHot; 3917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3918 if (numPoints) *numPoints = 0; 3919 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3920 PetscFunctionReturn(PETSC_SUCCESS); 3921 } 3922 3923 /*@ 3924 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3925 3926 Not Collective 3927 3928 Input Parameter: 3929 . dm - The `DMPLEX` 3930 3931 Output Parameters: 3932 + maxConeSize - The maximum number of in-edges 3933 - maxSupportSize - The maximum number of out-edges 3934 3935 Level: beginner 3936 3937 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3938 @*/ 3939 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3940 { 3941 DM_Plex *mesh = (DM_Plex *)dm->data; 3942 3943 PetscFunctionBegin; 3944 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3945 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3946 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3947 PetscFunctionReturn(PETSC_SUCCESS); 3948 } 3949 3950 PetscErrorCode DMSetUp_Plex(DM dm) 3951 { 3952 DM_Plex *mesh = (DM_Plex *)dm->data; 3953 PetscInt size, maxSupportSize; 3954 3955 PetscFunctionBegin; 3956 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3957 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3958 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3959 PetscCall(PetscMalloc1(size, &mesh->cones)); 3960 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3961 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3962 if (maxSupportSize) { 3963 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3964 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3965 PetscCall(PetscMalloc1(size, &mesh->supports)); 3966 } 3967 PetscFunctionReturn(PETSC_SUCCESS); 3968 } 3969 3970 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3971 { 3972 PetscFunctionBegin; 3973 if (subdm) PetscCall(DMClone(dm, subdm)); 3974 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3975 if (subdm) (*subdm)->useNatural = dm->useNatural; 3976 if (dm->useNatural && dm->sfMigration) { 3977 PetscSF sfNatural; 3978 3979 (*subdm)->sfMigration = dm->sfMigration; 3980 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3981 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3982 (*subdm)->sfNatural = sfNatural; 3983 } 3984 PetscFunctionReturn(PETSC_SUCCESS); 3985 } 3986 3987 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3988 { 3989 PetscInt i = 0; 3990 3991 PetscFunctionBegin; 3992 PetscCall(DMClone(dms[0], superdm)); 3993 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3994 (*superdm)->useNatural = PETSC_FALSE; 3995 for (i = 0; i < len; i++) { 3996 if (dms[i]->useNatural && dms[i]->sfMigration) { 3997 PetscSF sfNatural; 3998 3999 (*superdm)->sfMigration = dms[i]->sfMigration; 4000 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4001 (*superdm)->useNatural = PETSC_TRUE; 4002 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4003 (*superdm)->sfNatural = sfNatural; 4004 break; 4005 } 4006 } 4007 PetscFunctionReturn(PETSC_SUCCESS); 4008 } 4009 4010 /*@ 4011 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4012 4013 Not Collective 4014 4015 Input Parameter: 4016 . dm - The `DMPLEX` 4017 4018 Level: beginner 4019 4020 Note: 4021 This should be called after all calls to `DMPlexSetCone()` 4022 4023 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4024 @*/ 4025 PetscErrorCode DMPlexSymmetrize(DM dm) 4026 { 4027 DM_Plex *mesh = (DM_Plex *)dm->data; 4028 PetscInt *offsets; 4029 PetscInt supportSize; 4030 PetscInt pStart, pEnd, p; 4031 4032 PetscFunctionBegin; 4033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4034 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4035 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4036 /* Calculate support sizes */ 4037 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4038 for (p = pStart; p < pEnd; ++p) { 4039 PetscInt dof, off, c; 4040 4041 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4042 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4043 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4044 } 4045 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4046 /* Calculate supports */ 4047 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4048 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4049 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4050 for (p = pStart; p < pEnd; ++p) { 4051 PetscInt dof, off, c; 4052 4053 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4054 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4055 for (c = off; c < off + dof; ++c) { 4056 const PetscInt q = mesh->cones[c]; 4057 PetscInt offS; 4058 4059 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4060 4061 mesh->supports[offS + offsets[q]] = p; 4062 ++offsets[q]; 4063 } 4064 } 4065 PetscCall(PetscFree(offsets)); 4066 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4067 PetscFunctionReturn(PETSC_SUCCESS); 4068 } 4069 4070 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4071 { 4072 IS stratumIS; 4073 4074 PetscFunctionBegin; 4075 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4076 if (PetscDefined(USE_DEBUG)) { 4077 PetscInt qStart, qEnd, numLevels, level; 4078 PetscBool overlap = PETSC_FALSE; 4079 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4080 for (level = 0; level < numLevels; level++) { 4081 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4082 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4083 overlap = PETSC_TRUE; 4084 break; 4085 } 4086 } 4087 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); 4088 } 4089 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4090 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4091 PetscCall(ISDestroy(&stratumIS)); 4092 PetscFunctionReturn(PETSC_SUCCESS); 4093 } 4094 4095 /*@ 4096 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4097 4098 Collective 4099 4100 Input Parameter: 4101 . dm - The `DMPLEX` 4102 4103 Level: beginner 4104 4105 Notes: 4106 The strata group all points of the same grade, and this function calculates the strata. This 4107 grade can be seen as the height (or depth) of the point in the DAG. 4108 4109 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4110 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4111 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4112 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4113 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4114 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4115 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4116 4117 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4118 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4119 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 4120 to interpolate only that one (e0), so that 4121 .vb 4122 cone(c0) = {e0, v2} 4123 cone(e0) = {v0, v1} 4124 .ve 4125 If `DMPlexStratify()` is run on this mesh, it will give depths 4126 .vb 4127 depth 0 = {v0, v1, v2} 4128 depth 1 = {e0, c0} 4129 .ve 4130 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4131 4132 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4133 4134 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4135 @*/ 4136 PetscErrorCode DMPlexStratify(DM dm) 4137 { 4138 DM_Plex *mesh = (DM_Plex *)dm->data; 4139 DMLabel label; 4140 PetscInt pStart, pEnd, p; 4141 PetscInt numRoots = 0, numLeaves = 0; 4142 4143 PetscFunctionBegin; 4144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4145 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4146 4147 /* Create depth label */ 4148 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4149 PetscCall(DMCreateLabel(dm, "depth")); 4150 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4151 4152 { 4153 /* Initialize roots and count leaves */ 4154 PetscInt sMin = PETSC_MAX_INT; 4155 PetscInt sMax = PETSC_MIN_INT; 4156 PetscInt coneSize, supportSize; 4157 4158 for (p = pStart; p < pEnd; ++p) { 4159 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4160 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4161 if (!coneSize && supportSize) { 4162 sMin = PetscMin(p, sMin); 4163 sMax = PetscMax(p, sMax); 4164 ++numRoots; 4165 } else if (!supportSize && coneSize) { 4166 ++numLeaves; 4167 } else if (!supportSize && !coneSize) { 4168 /* Isolated points */ 4169 sMin = PetscMin(p, sMin); 4170 sMax = PetscMax(p, sMax); 4171 } 4172 } 4173 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4174 } 4175 4176 if (numRoots + numLeaves == (pEnd - pStart)) { 4177 PetscInt sMin = PETSC_MAX_INT; 4178 PetscInt sMax = PETSC_MIN_INT; 4179 PetscInt coneSize, supportSize; 4180 4181 for (p = pStart; p < pEnd; ++p) { 4182 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4183 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4184 if (!supportSize && coneSize) { 4185 sMin = PetscMin(p, sMin); 4186 sMax = PetscMax(p, sMax); 4187 } 4188 } 4189 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4190 } else { 4191 PetscInt level = 0; 4192 PetscInt qStart, qEnd, q; 4193 4194 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4195 while (qEnd > qStart) { 4196 PetscInt sMin = PETSC_MAX_INT; 4197 PetscInt sMax = PETSC_MIN_INT; 4198 4199 for (q = qStart; q < qEnd; ++q) { 4200 const PetscInt *support; 4201 PetscInt supportSize, s; 4202 4203 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4204 PetscCall(DMPlexGetSupport(dm, q, &support)); 4205 for (s = 0; s < supportSize; ++s) { 4206 sMin = PetscMin(support[s], sMin); 4207 sMax = PetscMax(support[s], sMax); 4208 } 4209 } 4210 PetscCall(DMLabelGetNumValues(label, &level)); 4211 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4212 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4213 } 4214 } 4215 { /* just in case there is an empty process */ 4216 PetscInt numValues, maxValues = 0, v; 4217 4218 PetscCall(DMLabelGetNumValues(label, &numValues)); 4219 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4220 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4221 } 4222 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4223 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4224 PetscFunctionReturn(PETSC_SUCCESS); 4225 } 4226 4227 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4228 { 4229 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4230 PetscInt dim, depth, pheight, coneSize; 4231 4232 PetscFunctionBeginHot; 4233 PetscCall(DMGetDimension(dm, &dim)); 4234 PetscCall(DMPlexGetDepth(dm, &depth)); 4235 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4236 pheight = depth - pdepth; 4237 if (depth <= 1) { 4238 switch (pdepth) { 4239 case 0: 4240 ct = DM_POLYTOPE_POINT; 4241 break; 4242 case 1: 4243 switch (coneSize) { 4244 case 2: 4245 ct = DM_POLYTOPE_SEGMENT; 4246 break; 4247 case 3: 4248 ct = DM_POLYTOPE_TRIANGLE; 4249 break; 4250 case 4: 4251 switch (dim) { 4252 case 2: 4253 ct = DM_POLYTOPE_QUADRILATERAL; 4254 break; 4255 case 3: 4256 ct = DM_POLYTOPE_TETRAHEDRON; 4257 break; 4258 default: 4259 break; 4260 } 4261 break; 4262 case 5: 4263 ct = DM_POLYTOPE_PYRAMID; 4264 break; 4265 case 6: 4266 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4267 break; 4268 case 8: 4269 ct = DM_POLYTOPE_HEXAHEDRON; 4270 break; 4271 default: 4272 break; 4273 } 4274 } 4275 } else { 4276 if (pdepth == 0) { 4277 ct = DM_POLYTOPE_POINT; 4278 } else if (pheight == 0) { 4279 switch (dim) { 4280 case 1: 4281 switch (coneSize) { 4282 case 2: 4283 ct = DM_POLYTOPE_SEGMENT; 4284 break; 4285 default: 4286 break; 4287 } 4288 break; 4289 case 2: 4290 switch (coneSize) { 4291 case 3: 4292 ct = DM_POLYTOPE_TRIANGLE; 4293 break; 4294 case 4: 4295 ct = DM_POLYTOPE_QUADRILATERAL; 4296 break; 4297 default: 4298 break; 4299 } 4300 break; 4301 case 3: 4302 switch (coneSize) { 4303 case 4: 4304 ct = DM_POLYTOPE_TETRAHEDRON; 4305 break; 4306 case 5: { 4307 const PetscInt *cone; 4308 PetscInt faceConeSize; 4309 4310 PetscCall(DMPlexGetCone(dm, p, &cone)); 4311 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4312 switch (faceConeSize) { 4313 case 3: 4314 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4315 break; 4316 case 4: 4317 ct = DM_POLYTOPE_PYRAMID; 4318 break; 4319 } 4320 } break; 4321 case 6: 4322 ct = DM_POLYTOPE_HEXAHEDRON; 4323 break; 4324 default: 4325 break; 4326 } 4327 break; 4328 default: 4329 break; 4330 } 4331 } else if (pheight > 0) { 4332 switch (coneSize) { 4333 case 2: 4334 ct = DM_POLYTOPE_SEGMENT; 4335 break; 4336 case 3: 4337 ct = DM_POLYTOPE_TRIANGLE; 4338 break; 4339 case 4: 4340 ct = DM_POLYTOPE_QUADRILATERAL; 4341 break; 4342 default: 4343 break; 4344 } 4345 } 4346 } 4347 *pt = ct; 4348 PetscFunctionReturn(PETSC_SUCCESS); 4349 } 4350 4351 /*@ 4352 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4353 4354 Collective 4355 4356 Input Parameter: 4357 . dm - The `DMPLEX` 4358 4359 Level: developer 4360 4361 Note: 4362 This function is normally called automatically when a cell type is requested. It creates an 4363 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4364 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4365 4366 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4367 4368 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4369 @*/ 4370 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4371 { 4372 DM_Plex *mesh; 4373 DMLabel ctLabel; 4374 PetscInt pStart, pEnd, p; 4375 4376 PetscFunctionBegin; 4377 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4378 mesh = (DM_Plex *)dm->data; 4379 PetscCall(DMCreateLabel(dm, "celltype")); 4380 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4381 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4382 PetscCall(PetscFree(mesh->cellTypes)); 4383 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4384 for (p = pStart; p < pEnd; ++p) { 4385 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4386 PetscInt pdepth; 4387 4388 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4389 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4390 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4391 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4392 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4393 } 4394 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4395 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4396 PetscFunctionReturn(PETSC_SUCCESS); 4397 } 4398 4399 /*@C 4400 DMPlexGetJoin - Get an array for the join of the set of points 4401 4402 Not Collective 4403 4404 Input Parameters: 4405 + dm - The `DMPLEX` object 4406 . numPoints - The number of input points for the join 4407 - points - The input points 4408 4409 Output Parameters: 4410 + numCoveredPoints - The number of points in the join 4411 - coveredPoints - The points in the join 4412 4413 Level: intermediate 4414 4415 Note: 4416 Currently, this is restricted to a single level join 4417 4418 Fortran Notes: 4419 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4420 4421 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4422 @*/ 4423 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4424 { 4425 DM_Plex *mesh = (DM_Plex *)dm->data; 4426 PetscInt *join[2]; 4427 PetscInt joinSize, i = 0; 4428 PetscInt dof, off, p, c, m; 4429 PetscInt maxSupportSize; 4430 4431 PetscFunctionBegin; 4432 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4433 PetscAssertPointer(points, 3); 4434 PetscAssertPointer(numCoveredPoints, 4); 4435 PetscAssertPointer(coveredPoints, 5); 4436 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4437 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4438 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4439 /* Copy in support of first point */ 4440 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4441 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4442 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4443 /* Check each successive support */ 4444 for (p = 1; p < numPoints; ++p) { 4445 PetscInt newJoinSize = 0; 4446 4447 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4448 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4449 for (c = 0; c < dof; ++c) { 4450 const PetscInt point = mesh->supports[off + c]; 4451 4452 for (m = 0; m < joinSize; ++m) { 4453 if (point == join[i][m]) { 4454 join[1 - i][newJoinSize++] = point; 4455 break; 4456 } 4457 } 4458 } 4459 joinSize = newJoinSize; 4460 i = 1 - i; 4461 } 4462 *numCoveredPoints = joinSize; 4463 *coveredPoints = join[i]; 4464 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4465 PetscFunctionReturn(PETSC_SUCCESS); 4466 } 4467 4468 /*@C 4469 DMPlexRestoreJoin - Restore an array for the join of the set of points 4470 4471 Not Collective 4472 4473 Input Parameters: 4474 + dm - The `DMPLEX` object 4475 . numPoints - The number of input points for the join 4476 - points - The input points 4477 4478 Output Parameters: 4479 + numCoveredPoints - The number of points in the join 4480 - coveredPoints - The points in the join 4481 4482 Level: intermediate 4483 4484 Fortran Notes: 4485 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4486 4487 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4488 @*/ 4489 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4490 { 4491 PetscFunctionBegin; 4492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4493 if (points) PetscAssertPointer(points, 3); 4494 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4495 PetscAssertPointer(coveredPoints, 5); 4496 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4497 if (numCoveredPoints) *numCoveredPoints = 0; 4498 PetscFunctionReturn(PETSC_SUCCESS); 4499 } 4500 4501 /*@C 4502 DMPlexGetFullJoin - Get an array for the join of the set of points 4503 4504 Not Collective 4505 4506 Input Parameters: 4507 + dm - The `DMPLEX` object 4508 . numPoints - The number of input points for the join 4509 - points - The input points 4510 4511 Output Parameters: 4512 + numCoveredPoints - The number of points in the join 4513 - coveredPoints - The points in the join 4514 4515 Level: intermediate 4516 4517 Fortran Notes: 4518 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4519 4520 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4521 @*/ 4522 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4523 { 4524 PetscInt *offsets, **closures; 4525 PetscInt *join[2]; 4526 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4527 PetscInt p, d, c, m, ms; 4528 4529 PetscFunctionBegin; 4530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4531 PetscAssertPointer(points, 3); 4532 PetscAssertPointer(numCoveredPoints, 4); 4533 PetscAssertPointer(coveredPoints, 5); 4534 4535 PetscCall(DMPlexGetDepth(dm, &depth)); 4536 PetscCall(PetscCalloc1(numPoints, &closures)); 4537 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4538 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4539 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4540 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4541 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4542 4543 for (p = 0; p < numPoints; ++p) { 4544 PetscInt closureSize; 4545 4546 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4547 4548 offsets[p * (depth + 2) + 0] = 0; 4549 for (d = 0; d < depth + 1; ++d) { 4550 PetscInt pStart, pEnd, i; 4551 4552 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4553 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4554 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4555 offsets[p * (depth + 2) + d + 1] = i; 4556 break; 4557 } 4558 } 4559 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4560 } 4561 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); 4562 } 4563 for (d = 0; d < depth + 1; ++d) { 4564 PetscInt dof; 4565 4566 /* Copy in support of first point */ 4567 dof = offsets[d + 1] - offsets[d]; 4568 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4569 /* Check each successive cone */ 4570 for (p = 1; p < numPoints && joinSize; ++p) { 4571 PetscInt newJoinSize = 0; 4572 4573 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4574 for (c = 0; c < dof; ++c) { 4575 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4576 4577 for (m = 0; m < joinSize; ++m) { 4578 if (point == join[i][m]) { 4579 join[1 - i][newJoinSize++] = point; 4580 break; 4581 } 4582 } 4583 } 4584 joinSize = newJoinSize; 4585 i = 1 - i; 4586 } 4587 if (joinSize) break; 4588 } 4589 *numCoveredPoints = joinSize; 4590 *coveredPoints = join[i]; 4591 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4592 PetscCall(PetscFree(closures)); 4593 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4594 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4595 PetscFunctionReturn(PETSC_SUCCESS); 4596 } 4597 4598 /*@C 4599 DMPlexGetMeet - Get an array for the meet of the set of points 4600 4601 Not Collective 4602 4603 Input Parameters: 4604 + dm - The `DMPLEX` object 4605 . numPoints - The number of input points for the meet 4606 - points - The input points 4607 4608 Output Parameters: 4609 + numCoveringPoints - The number of points in the meet 4610 - coveringPoints - The points in the meet 4611 4612 Level: intermediate 4613 4614 Note: 4615 Currently, this is restricted to a single level meet 4616 4617 Fortran Notes: 4618 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4619 4620 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4621 @*/ 4622 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4623 { 4624 DM_Plex *mesh = (DM_Plex *)dm->data; 4625 PetscInt *meet[2]; 4626 PetscInt meetSize, i = 0; 4627 PetscInt dof, off, p, c, m; 4628 PetscInt maxConeSize; 4629 4630 PetscFunctionBegin; 4631 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4632 PetscAssertPointer(points, 3); 4633 PetscAssertPointer(numCoveringPoints, 4); 4634 PetscAssertPointer(coveringPoints, 5); 4635 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4636 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4637 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4638 /* Copy in cone of first point */ 4639 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4640 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4641 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4642 /* Check each successive cone */ 4643 for (p = 1; p < numPoints; ++p) { 4644 PetscInt newMeetSize = 0; 4645 4646 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4647 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4648 for (c = 0; c < dof; ++c) { 4649 const PetscInt point = mesh->cones[off + c]; 4650 4651 for (m = 0; m < meetSize; ++m) { 4652 if (point == meet[i][m]) { 4653 meet[1 - i][newMeetSize++] = point; 4654 break; 4655 } 4656 } 4657 } 4658 meetSize = newMeetSize; 4659 i = 1 - i; 4660 } 4661 *numCoveringPoints = meetSize; 4662 *coveringPoints = meet[i]; 4663 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4664 PetscFunctionReturn(PETSC_SUCCESS); 4665 } 4666 4667 /*@C 4668 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4669 4670 Not Collective 4671 4672 Input Parameters: 4673 + dm - The `DMPLEX` object 4674 . numPoints - The number of input points for the meet 4675 - points - The input points 4676 4677 Output Parameters: 4678 + numCoveredPoints - The number of points in the meet 4679 - coveredPoints - The points in the meet 4680 4681 Level: intermediate 4682 4683 Fortran Notes: 4684 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4685 4686 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4687 @*/ 4688 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4689 { 4690 PetscFunctionBegin; 4691 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4692 if (points) PetscAssertPointer(points, 3); 4693 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4694 PetscAssertPointer(coveredPoints, 5); 4695 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4696 if (numCoveredPoints) *numCoveredPoints = 0; 4697 PetscFunctionReturn(PETSC_SUCCESS); 4698 } 4699 4700 /*@C 4701 DMPlexGetFullMeet - Get an array for the meet of the set of points 4702 4703 Not Collective 4704 4705 Input Parameters: 4706 + dm - The `DMPLEX` object 4707 . numPoints - The number of input points for the meet 4708 - points - The input points 4709 4710 Output Parameters: 4711 + numCoveredPoints - The number of points in the meet 4712 - coveredPoints - The points in the meet 4713 4714 Level: intermediate 4715 4716 Fortran Notes: 4717 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4718 4719 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4720 @*/ 4721 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4722 { 4723 PetscInt *offsets, **closures; 4724 PetscInt *meet[2]; 4725 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4726 PetscInt p, h, c, m, mc; 4727 4728 PetscFunctionBegin; 4729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4730 PetscAssertPointer(points, 3); 4731 PetscAssertPointer(numCoveredPoints, 4); 4732 PetscAssertPointer(coveredPoints, 5); 4733 4734 PetscCall(DMPlexGetDepth(dm, &height)); 4735 PetscCall(PetscMalloc1(numPoints, &closures)); 4736 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4737 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4738 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4739 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4740 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4741 4742 for (p = 0; p < numPoints; ++p) { 4743 PetscInt closureSize; 4744 4745 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4746 4747 offsets[p * (height + 2) + 0] = 0; 4748 for (h = 0; h < height + 1; ++h) { 4749 PetscInt pStart, pEnd, i; 4750 4751 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4752 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4753 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4754 offsets[p * (height + 2) + h + 1] = i; 4755 break; 4756 } 4757 } 4758 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4759 } 4760 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); 4761 } 4762 for (h = 0; h < height + 1; ++h) { 4763 PetscInt dof; 4764 4765 /* Copy in cone of first point */ 4766 dof = offsets[h + 1] - offsets[h]; 4767 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4768 /* Check each successive cone */ 4769 for (p = 1; p < numPoints && meetSize; ++p) { 4770 PetscInt newMeetSize = 0; 4771 4772 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4773 for (c = 0; c < dof; ++c) { 4774 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4775 4776 for (m = 0; m < meetSize; ++m) { 4777 if (point == meet[i][m]) { 4778 meet[1 - i][newMeetSize++] = point; 4779 break; 4780 } 4781 } 4782 } 4783 meetSize = newMeetSize; 4784 i = 1 - i; 4785 } 4786 if (meetSize) break; 4787 } 4788 *numCoveredPoints = meetSize; 4789 *coveredPoints = meet[i]; 4790 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4791 PetscCall(PetscFree(closures)); 4792 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4793 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4794 PetscFunctionReturn(PETSC_SUCCESS); 4795 } 4796 4797 /*@C 4798 DMPlexEqual - Determine if two `DM` have the same topology 4799 4800 Not Collective 4801 4802 Input Parameters: 4803 + dmA - A `DMPLEX` object 4804 - dmB - A `DMPLEX` object 4805 4806 Output Parameter: 4807 . equal - `PETSC_TRUE` if the topologies are identical 4808 4809 Level: intermediate 4810 4811 Note: 4812 We are not solving graph isomorphism, so we do not permute. 4813 4814 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4815 @*/ 4816 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4817 { 4818 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4819 4820 PetscFunctionBegin; 4821 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4822 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4823 PetscAssertPointer(equal, 3); 4824 4825 *equal = PETSC_FALSE; 4826 PetscCall(DMPlexGetDepth(dmA, &depth)); 4827 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4828 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 4829 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4830 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4831 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 4832 for (p = pStart; p < pEnd; ++p) { 4833 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4834 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4835 4836 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4837 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4838 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4839 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4840 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4841 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4842 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4843 for (c = 0; c < coneSize; ++c) { 4844 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4845 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4846 } 4847 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4848 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4849 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4850 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4851 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4852 for (s = 0; s < supportSize; ++s) { 4853 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 4854 } 4855 } 4856 *equal = PETSC_TRUE; 4857 PetscFunctionReturn(PETSC_SUCCESS); 4858 } 4859 4860 /*@C 4861 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4862 4863 Not Collective 4864 4865 Input Parameters: 4866 + dm - The `DMPLEX` 4867 . cellDim - The cell dimension 4868 - numCorners - The number of vertices on a cell 4869 4870 Output Parameter: 4871 . numFaceVertices - The number of vertices on a face 4872 4873 Level: developer 4874 4875 Note: 4876 Of course this can only work for a restricted set of symmetric shapes 4877 4878 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4879 @*/ 4880 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4881 { 4882 MPI_Comm comm; 4883 4884 PetscFunctionBegin; 4885 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4886 PetscAssertPointer(numFaceVertices, 4); 4887 switch (cellDim) { 4888 case 0: 4889 *numFaceVertices = 0; 4890 break; 4891 case 1: 4892 *numFaceVertices = 1; 4893 break; 4894 case 2: 4895 switch (numCorners) { 4896 case 3: /* triangle */ 4897 *numFaceVertices = 2; /* Edge has 2 vertices */ 4898 break; 4899 case 4: /* quadrilateral */ 4900 *numFaceVertices = 2; /* Edge has 2 vertices */ 4901 break; 4902 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4903 *numFaceVertices = 3; /* Edge has 3 vertices */ 4904 break; 4905 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4906 *numFaceVertices = 3; /* Edge has 3 vertices */ 4907 break; 4908 default: 4909 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4910 } 4911 break; 4912 case 3: 4913 switch (numCorners) { 4914 case 4: /* tetradehdron */ 4915 *numFaceVertices = 3; /* Face has 3 vertices */ 4916 break; 4917 case 6: /* tet cohesive cells */ 4918 *numFaceVertices = 4; /* Face has 4 vertices */ 4919 break; 4920 case 8: /* hexahedron */ 4921 *numFaceVertices = 4; /* Face has 4 vertices */ 4922 break; 4923 case 9: /* tet cohesive Lagrange cells */ 4924 *numFaceVertices = 6; /* Face has 6 vertices */ 4925 break; 4926 case 10: /* quadratic tetrahedron */ 4927 *numFaceVertices = 6; /* Face has 6 vertices */ 4928 break; 4929 case 12: /* hex cohesive Lagrange cells */ 4930 *numFaceVertices = 6; /* Face has 6 vertices */ 4931 break; 4932 case 18: /* quadratic tet cohesive Lagrange cells */ 4933 *numFaceVertices = 6; /* Face has 6 vertices */ 4934 break; 4935 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4936 *numFaceVertices = 9; /* Face has 9 vertices */ 4937 break; 4938 default: 4939 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4940 } 4941 break; 4942 default: 4943 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4944 } 4945 PetscFunctionReturn(PETSC_SUCCESS); 4946 } 4947 4948 /*@ 4949 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 4950 4951 Not Collective 4952 4953 Input Parameter: 4954 . dm - The `DMPLEX` object 4955 4956 Output Parameter: 4957 . depthLabel - The `DMLabel` recording point depth 4958 4959 Level: developer 4960 4961 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4962 @*/ 4963 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4964 { 4965 PetscFunctionBegin; 4966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4967 PetscAssertPointer(depthLabel, 2); 4968 *depthLabel = dm->depthLabel; 4969 PetscFunctionReturn(PETSC_SUCCESS); 4970 } 4971 4972 /*@ 4973 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4974 4975 Not Collective 4976 4977 Input Parameter: 4978 . dm - The `DMPLEX` object 4979 4980 Output Parameter: 4981 . depth - The number of strata (breadth first levels) in the DAG 4982 4983 Level: developer 4984 4985 Notes: 4986 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 4987 4988 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 4989 4990 An empty mesh gives -1. 4991 4992 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4993 @*/ 4994 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4995 { 4996 DM_Plex *mesh = (DM_Plex *)dm->data; 4997 DMLabel label; 4998 PetscInt d = 0; 4999 5000 PetscFunctionBegin; 5001 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5002 PetscAssertPointer(depth, 2); 5003 if (mesh->tr) { 5004 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5005 } else { 5006 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5007 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5008 *depth = d - 1; 5009 } 5010 PetscFunctionReturn(PETSC_SUCCESS); 5011 } 5012 5013 /*@ 5014 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5015 5016 Not Collective 5017 5018 Input Parameters: 5019 + dm - The `DMPLEX` object 5020 - depth - The requested depth 5021 5022 Output Parameters: 5023 + start - The first point at this `depth` 5024 - end - One beyond the last point at this `depth` 5025 5026 Level: developer 5027 5028 Notes: 5029 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5030 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5031 higher dimension, e.g., "edges". 5032 5033 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5034 @*/ 5035 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5036 { 5037 DM_Plex *mesh = (DM_Plex *)dm->data; 5038 DMLabel label; 5039 PetscInt pStart, pEnd; 5040 5041 PetscFunctionBegin; 5042 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5043 if (start) { 5044 PetscAssertPointer(start, 3); 5045 *start = 0; 5046 } 5047 if (end) { 5048 PetscAssertPointer(end, 4); 5049 *end = 0; 5050 } 5051 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5052 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5053 if (depth < 0) { 5054 if (start) *start = pStart; 5055 if (end) *end = pEnd; 5056 PetscFunctionReturn(PETSC_SUCCESS); 5057 } 5058 if (mesh->tr) { 5059 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5060 } else { 5061 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5062 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5063 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5064 } 5065 PetscFunctionReturn(PETSC_SUCCESS); 5066 } 5067 5068 /*@ 5069 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5070 5071 Not Collective 5072 5073 Input Parameters: 5074 + dm - The `DMPLEX` object 5075 - height - The requested height 5076 5077 Output Parameters: 5078 + start - The first point at this `height` 5079 - end - One beyond the last point at this `height` 5080 5081 Level: developer 5082 5083 Notes: 5084 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5085 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5086 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5087 5088 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5089 @*/ 5090 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5091 { 5092 DMLabel label; 5093 PetscInt depth, pStart, pEnd; 5094 5095 PetscFunctionBegin; 5096 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5097 if (start) { 5098 PetscAssertPointer(start, 3); 5099 *start = 0; 5100 } 5101 if (end) { 5102 PetscAssertPointer(end, 4); 5103 *end = 0; 5104 } 5105 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5106 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5107 if (height < 0) { 5108 if (start) *start = pStart; 5109 if (end) *end = pEnd; 5110 PetscFunctionReturn(PETSC_SUCCESS); 5111 } 5112 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5113 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5114 else PetscCall(DMGetDimension(dm, &depth)); 5115 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5116 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5117 PetscFunctionReturn(PETSC_SUCCESS); 5118 } 5119 5120 /*@ 5121 DMPlexGetPointDepth - Get the `depth` of a given point 5122 5123 Not Collective 5124 5125 Input Parameters: 5126 + dm - The `DMPLEX` object 5127 - point - The point 5128 5129 Output Parameter: 5130 . depth - The depth of the `point` 5131 5132 Level: intermediate 5133 5134 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5135 @*/ 5136 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5137 { 5138 PetscFunctionBegin; 5139 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5140 PetscAssertPointer(depth, 3); 5141 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5142 PetscFunctionReturn(PETSC_SUCCESS); 5143 } 5144 5145 /*@ 5146 DMPlexGetPointHeight - Get the `height` of a given point 5147 5148 Not Collective 5149 5150 Input Parameters: 5151 + dm - The `DMPLEX` object 5152 - point - The point 5153 5154 Output Parameter: 5155 . height - The height of the `point` 5156 5157 Level: intermediate 5158 5159 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5160 @*/ 5161 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5162 { 5163 PetscInt n, pDepth; 5164 5165 PetscFunctionBegin; 5166 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5167 PetscAssertPointer(height, 3); 5168 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5169 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5170 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5171 PetscFunctionReturn(PETSC_SUCCESS); 5172 } 5173 5174 /*@ 5175 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5176 5177 Not Collective 5178 5179 Input Parameter: 5180 . dm - The `DMPLEX` object 5181 5182 Output Parameter: 5183 . celltypeLabel - The `DMLabel` recording cell polytope type 5184 5185 Level: developer 5186 5187 Note: 5188 This function will trigger automatica computation of cell types. This can be disabled by calling 5189 `DMCreateLabel`(dm, "celltype") beforehand. 5190 5191 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5192 @*/ 5193 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5194 { 5195 PetscFunctionBegin; 5196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5197 PetscAssertPointer(celltypeLabel, 2); 5198 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5199 *celltypeLabel = dm->celltypeLabel; 5200 PetscFunctionReturn(PETSC_SUCCESS); 5201 } 5202 5203 /*@ 5204 DMPlexGetCellType - Get the polytope type of a given cell 5205 5206 Not Collective 5207 5208 Input Parameters: 5209 + dm - The `DMPLEX` object 5210 - cell - The cell 5211 5212 Output Parameter: 5213 . celltype - The polytope type of the cell 5214 5215 Level: intermediate 5216 5217 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5218 @*/ 5219 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5220 { 5221 DM_Plex *mesh = (DM_Plex *)dm->data; 5222 DMLabel label; 5223 PetscInt ct; 5224 5225 PetscFunctionBegin; 5226 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5227 PetscAssertPointer(celltype, 3); 5228 if (mesh->tr) { 5229 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5230 } else { 5231 PetscInt pStart, pEnd; 5232 5233 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5234 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5235 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5236 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5237 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5238 for (PetscInt p = pStart; p < pEnd; p++) { 5239 PetscCall(DMLabelGetValue(label, p, &ct)); 5240 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5241 } 5242 } 5243 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5244 if (PetscDefined(USE_DEBUG)) { 5245 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5246 PetscCall(DMLabelGetValue(label, cell, &ct)); 5247 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5248 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5249 } 5250 } 5251 PetscFunctionReturn(PETSC_SUCCESS); 5252 } 5253 5254 /*@ 5255 DMPlexSetCellType - Set the polytope type of a given cell 5256 5257 Not Collective 5258 5259 Input Parameters: 5260 + dm - The `DMPLEX` object 5261 . cell - The cell 5262 - celltype - The polytope type of the cell 5263 5264 Level: advanced 5265 5266 Note: 5267 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5268 is executed. This function will override the computed type. However, if automatic classification will not succeed 5269 and a user wants to manually specify all types, the classification must be disabled by calling 5270 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5271 5272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5273 @*/ 5274 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5275 { 5276 DM_Plex *mesh = (DM_Plex *)dm->data; 5277 DMLabel label; 5278 PetscInt pStart, pEnd; 5279 5280 PetscFunctionBegin; 5281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5282 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5283 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5284 PetscCall(DMLabelSetValue(label, cell, celltype)); 5285 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5286 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5287 PetscFunctionReturn(PETSC_SUCCESS); 5288 } 5289 5290 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5291 { 5292 PetscSection section, s; 5293 Mat m; 5294 PetscInt maxHeight; 5295 const char *prefix; 5296 5297 PetscFunctionBegin; 5298 PetscCall(DMClone(dm, cdm)); 5299 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5300 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5301 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5302 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5303 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5304 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5305 PetscCall(DMSetLocalSection(*cdm, section)); 5306 PetscCall(PetscSectionDestroy(§ion)); 5307 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5308 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5309 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5310 PetscCall(PetscSectionDestroy(&s)); 5311 PetscCall(MatDestroy(&m)); 5312 5313 PetscCall(DMSetNumFields(*cdm, 1)); 5314 PetscCall(DMCreateDS(*cdm)); 5315 (*cdm)->cloneOpts = PETSC_TRUE; 5316 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5317 PetscFunctionReturn(PETSC_SUCCESS); 5318 } 5319 5320 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5321 { 5322 Vec coordsLocal, cellCoordsLocal; 5323 DM coordsDM, cellCoordsDM; 5324 5325 PetscFunctionBegin; 5326 *field = NULL; 5327 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5328 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5329 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5330 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5331 if (coordsLocal && coordsDM) { 5332 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5333 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5334 } 5335 PetscFunctionReturn(PETSC_SUCCESS); 5336 } 5337 5338 /*@C 5339 DMPlexGetConeSection - Return a section which describes the layout of cone data 5340 5341 Not Collective 5342 5343 Input Parameter: 5344 . dm - The `DMPLEX` object 5345 5346 Output Parameter: 5347 . section - The `PetscSection` object 5348 5349 Level: developer 5350 5351 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5352 @*/ 5353 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5354 { 5355 DM_Plex *mesh = (DM_Plex *)dm->data; 5356 5357 PetscFunctionBegin; 5358 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5359 if (section) *section = mesh->coneSection; 5360 PetscFunctionReturn(PETSC_SUCCESS); 5361 } 5362 5363 /*@C 5364 DMPlexGetSupportSection - Return a section which describes the layout of support data 5365 5366 Not Collective 5367 5368 Input Parameter: 5369 . dm - The `DMPLEX` object 5370 5371 Output Parameter: 5372 . section - The `PetscSection` object 5373 5374 Level: developer 5375 5376 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5377 @*/ 5378 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5379 { 5380 DM_Plex *mesh = (DM_Plex *)dm->data; 5381 5382 PetscFunctionBegin; 5383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5384 if (section) *section = mesh->supportSection; 5385 PetscFunctionReturn(PETSC_SUCCESS); 5386 } 5387 5388 /*@C 5389 DMPlexGetCones - Return cone data 5390 5391 Not Collective 5392 5393 Input Parameter: 5394 . dm - The `DMPLEX` object 5395 5396 Output Parameter: 5397 . cones - The cone for each point 5398 5399 Level: developer 5400 5401 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5402 @*/ 5403 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5404 { 5405 DM_Plex *mesh = (DM_Plex *)dm->data; 5406 5407 PetscFunctionBegin; 5408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5409 if (cones) *cones = mesh->cones; 5410 PetscFunctionReturn(PETSC_SUCCESS); 5411 } 5412 5413 /*@C 5414 DMPlexGetConeOrientations - Return cone orientation data 5415 5416 Not Collective 5417 5418 Input Parameter: 5419 . dm - The `DMPLEX` object 5420 5421 Output Parameter: 5422 . coneOrientations - The array of cone orientations for all points 5423 5424 Level: developer 5425 5426 Notes: 5427 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5428 5429 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5430 5431 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5432 @*/ 5433 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5434 { 5435 DM_Plex *mesh = (DM_Plex *)dm->data; 5436 5437 PetscFunctionBegin; 5438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5439 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5440 PetscFunctionReturn(PETSC_SUCCESS); 5441 } 5442 5443 /******************************** FEM Support **********************************/ 5444 5445 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5446 { 5447 PetscInt depth; 5448 5449 PetscFunctionBegin; 5450 PetscCall(DMPlexGetDepth(plex, &depth)); 5451 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5452 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5453 PetscFunctionReturn(PETSC_SUCCESS); 5454 } 5455 5456 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5457 { 5458 PetscInt depth; 5459 5460 PetscFunctionBegin; 5461 PetscCall(DMPlexGetDepth(plex, &depth)); 5462 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5463 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5464 PetscFunctionReturn(PETSC_SUCCESS); 5465 } 5466 5467 /* 5468 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5469 representing a line in the section. 5470 */ 5471 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5472 { 5473 PetscFunctionBeginHot; 5474 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5475 if (line < 0) { 5476 *k = 0; 5477 *Nc = 0; 5478 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5479 *k = 1; 5480 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5481 /* An order k SEM disc has k-1 dofs on an edge */ 5482 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5483 *k = *k / *Nc + 1; 5484 } 5485 PetscFunctionReturn(PETSC_SUCCESS); 5486 } 5487 5488 /*@ 5489 5490 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5491 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5492 section provided (or the section of the `DM`). 5493 5494 Input Parameters: 5495 + dm - The `DM` 5496 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5497 - section - The `PetscSection` to reorder, or `NULL` for the default section 5498 5499 Example: 5500 A typical interpolated single-quad mesh might order points as 5501 .vb 5502 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5503 5504 v4 -- e6 -- v3 5505 | | 5506 e7 c0 e8 5507 | | 5508 v1 -- e5 -- v2 5509 .ve 5510 5511 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5512 dofs in the order of points, e.g., 5513 .vb 5514 c0 -> [0,1,2,3] 5515 v1 -> [4] 5516 ... 5517 e5 -> [8, 9] 5518 .ve 5519 5520 which corresponds to the dofs 5521 .vb 5522 6 10 11 7 5523 13 2 3 15 5524 12 0 1 14 5525 4 8 9 5 5526 .ve 5527 5528 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5529 .vb 5530 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5531 .ve 5532 5533 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5534 .vb 5535 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5536 .ve 5537 5538 Level: developer 5539 5540 Notes: 5541 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5542 degree of the basis. 5543 5544 This is required to run with libCEED. 5545 5546 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5547 @*/ 5548 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5549 { 5550 DMLabel label; 5551 PetscInt dim, depth = -1, eStart = -1, Nf; 5552 PetscBool vertexchart; 5553 5554 PetscFunctionBegin; 5555 PetscCall(DMGetDimension(dm, &dim)); 5556 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5557 if (point < 0) { 5558 PetscInt sStart, sEnd; 5559 5560 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5561 point = sEnd - sStart ? sStart : point; 5562 } 5563 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5564 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5565 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5566 if (depth == 1) { 5567 eStart = point; 5568 } else if (depth == dim) { 5569 const PetscInt *cone; 5570 5571 PetscCall(DMPlexGetCone(dm, point, &cone)); 5572 if (dim == 2) eStart = cone[0]; 5573 else if (dim == 3) { 5574 const PetscInt *cone2; 5575 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5576 eStart = cone2[0]; 5577 } 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); 5578 } 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); 5579 { /* Determine whether the chart covers all points or just vertices. */ 5580 PetscInt pStart, pEnd, cStart, cEnd; 5581 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5582 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5583 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5584 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5585 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5586 } 5587 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5588 for (PetscInt d = 1; d <= dim; d++) { 5589 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5590 PetscInt *perm; 5591 5592 for (f = 0; f < Nf; ++f) { 5593 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5594 size += PetscPowInt(k + 1, d) * Nc; 5595 } 5596 PetscCall(PetscMalloc1(size, &perm)); 5597 for (f = 0; f < Nf; ++f) { 5598 switch (d) { 5599 case 1: 5600 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5601 /* 5602 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5603 We want [ vtx0; edge of length k-1; vtx1 ] 5604 */ 5605 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5606 for (i = 0; i < k - 1; i++) 5607 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5608 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5609 foffset = offset; 5610 break; 5611 case 2: 5612 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5613 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5614 /* The SEM order is 5615 5616 v_lb, {e_b}, v_rb, 5617 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5618 v_lt, reverse {e_t}, v_rt 5619 */ 5620 { 5621 const PetscInt of = 0; 5622 const PetscInt oeb = of + PetscSqr(k - 1); 5623 const PetscInt oer = oeb + (k - 1); 5624 const PetscInt oet = oer + (k - 1); 5625 const PetscInt oel = oet + (k - 1); 5626 const PetscInt ovlb = oel + (k - 1); 5627 const PetscInt ovrb = ovlb + 1; 5628 const PetscInt ovrt = ovrb + 1; 5629 const PetscInt ovlt = ovrt + 1; 5630 PetscInt o; 5631 5632 /* bottom */ 5633 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5634 for (o = oeb; o < oer; ++o) 5635 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5636 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5637 /* middle */ 5638 for (i = 0; i < k - 1; ++i) { 5639 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5640 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5641 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5642 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5643 } 5644 /* top */ 5645 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5646 for (o = oel - 1; o >= oet; --o) 5647 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5648 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5649 foffset = offset; 5650 } 5651 break; 5652 case 3: 5653 /* The original hex closure is 5654 5655 {c, 5656 f_b, f_t, f_f, f_b, f_r, f_l, 5657 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5658 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5659 */ 5660 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5661 /* The SEM order is 5662 Bottom Slice 5663 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5664 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5665 v_blb, {e_bb}, v_brb, 5666 5667 Middle Slice (j) 5668 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5669 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5670 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5671 5672 Top Slice 5673 v_tlf, {e_tf}, v_trf, 5674 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5675 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5676 */ 5677 { 5678 const PetscInt oc = 0; 5679 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5680 const PetscInt oft = ofb + PetscSqr(k - 1); 5681 const PetscInt off = oft + PetscSqr(k - 1); 5682 const PetscInt ofk = off + PetscSqr(k - 1); 5683 const PetscInt ofr = ofk + PetscSqr(k - 1); 5684 const PetscInt ofl = ofr + PetscSqr(k - 1); 5685 const PetscInt oebl = ofl + PetscSqr(k - 1); 5686 const PetscInt oebb = oebl + (k - 1); 5687 const PetscInt oebr = oebb + (k - 1); 5688 const PetscInt oebf = oebr + (k - 1); 5689 const PetscInt oetf = oebf + (k - 1); 5690 const PetscInt oetr = oetf + (k - 1); 5691 const PetscInt oetb = oetr + (k - 1); 5692 const PetscInt oetl = oetb + (k - 1); 5693 const PetscInt oerf = oetl + (k - 1); 5694 const PetscInt oelf = oerf + (k - 1); 5695 const PetscInt oelb = oelf + (k - 1); 5696 const PetscInt oerb = oelb + (k - 1); 5697 const PetscInt ovblf = oerb + (k - 1); 5698 const PetscInt ovblb = ovblf + 1; 5699 const PetscInt ovbrb = ovblb + 1; 5700 const PetscInt ovbrf = ovbrb + 1; 5701 const PetscInt ovtlf = ovbrf + 1; 5702 const PetscInt ovtrf = ovtlf + 1; 5703 const PetscInt ovtrb = ovtrf + 1; 5704 const PetscInt ovtlb = ovtrb + 1; 5705 PetscInt o, n; 5706 5707 /* Bottom Slice */ 5708 /* bottom */ 5709 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5710 for (o = oetf - 1; o >= oebf; --o) 5711 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5712 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5713 /* middle */ 5714 for (i = 0; i < k - 1; ++i) { 5715 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5716 for (n = 0; n < k - 1; ++n) { 5717 o = ofb + n * (k - 1) + i; 5718 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5719 } 5720 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5721 } 5722 /* top */ 5723 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5724 for (o = oebb; o < oebr; ++o) 5725 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5726 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5727 5728 /* Middle Slice */ 5729 for (j = 0; j < k - 1; ++j) { 5730 /* bottom */ 5731 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5732 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5733 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5734 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5735 /* middle */ 5736 for (i = 0; i < k - 1; ++i) { 5737 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5738 for (n = 0; n < k - 1; ++n) 5739 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5740 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5741 } 5742 /* top */ 5743 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5744 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5745 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5746 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5747 } 5748 5749 /* Top Slice */ 5750 /* bottom */ 5751 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5752 for (o = oetf; o < oetr; ++o) 5753 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5754 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5755 /* middle */ 5756 for (i = 0; i < k - 1; ++i) { 5757 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5758 for (n = 0; n < k - 1; ++n) 5759 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5760 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5761 } 5762 /* top */ 5763 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5764 for (o = oetl - 1; o >= oetb; --o) 5765 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5766 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5767 5768 foffset = offset; 5769 } 5770 break; 5771 default: 5772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5773 } 5774 } 5775 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5776 /* Check permutation */ 5777 { 5778 PetscInt *check; 5779 5780 PetscCall(PetscMalloc1(size, &check)); 5781 for (i = 0; i < size; ++i) { 5782 check[i] = -1; 5783 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5784 } 5785 for (i = 0; i < size; ++i) check[perm[i]] = i; 5786 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5787 PetscCall(PetscFree(check)); 5788 } 5789 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5790 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5791 PetscInt *loc_perm; 5792 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5793 for (PetscInt i = 0; i < size; i++) { 5794 loc_perm[i] = perm[i]; 5795 loc_perm[size + i] = size + perm[i]; 5796 } 5797 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5798 } 5799 } 5800 PetscFunctionReturn(PETSC_SUCCESS); 5801 } 5802 5803 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5804 { 5805 PetscDS prob; 5806 PetscInt depth, Nf, h; 5807 DMLabel label; 5808 5809 PetscFunctionBeginHot; 5810 PetscCall(DMGetDS(dm, &prob)); 5811 Nf = prob->Nf; 5812 label = dm->depthLabel; 5813 *dspace = NULL; 5814 if (field < Nf) { 5815 PetscObject disc = prob->disc[field]; 5816 5817 if (disc->classid == PETSCFE_CLASSID) { 5818 PetscDualSpace dsp; 5819 5820 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5821 PetscCall(DMLabelGetNumValues(label, &depth)); 5822 PetscCall(DMLabelGetValue(label, point, &h)); 5823 h = depth - 1 - h; 5824 if (h) { 5825 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5826 } else { 5827 *dspace = dsp; 5828 } 5829 } 5830 } 5831 PetscFunctionReturn(PETSC_SUCCESS); 5832 } 5833 5834 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5835 { 5836 PetscScalar *array; 5837 const PetscScalar *vArray; 5838 const PetscInt *cone, *coneO; 5839 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5840 5841 PetscFunctionBeginHot; 5842 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5843 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5844 PetscCall(DMPlexGetCone(dm, point, &cone)); 5845 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5846 if (!values || !*values) { 5847 if ((point >= pStart) && (point < pEnd)) { 5848 PetscInt dof; 5849 5850 PetscCall(PetscSectionGetDof(section, point, &dof)); 5851 size += dof; 5852 } 5853 for (p = 0; p < numPoints; ++p) { 5854 const PetscInt cp = cone[p]; 5855 PetscInt dof; 5856 5857 if ((cp < pStart) || (cp >= pEnd)) continue; 5858 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5859 size += dof; 5860 } 5861 if (!values) { 5862 if (csize) *csize = size; 5863 PetscFunctionReturn(PETSC_SUCCESS); 5864 } 5865 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5866 } else { 5867 array = *values; 5868 } 5869 size = 0; 5870 PetscCall(VecGetArrayRead(v, &vArray)); 5871 if ((point >= pStart) && (point < pEnd)) { 5872 PetscInt dof, off, d; 5873 const PetscScalar *varr; 5874 5875 PetscCall(PetscSectionGetDof(section, point, &dof)); 5876 PetscCall(PetscSectionGetOffset(section, point, &off)); 5877 varr = &vArray[off]; 5878 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5879 size += dof; 5880 } 5881 for (p = 0; p < numPoints; ++p) { 5882 const PetscInt cp = cone[p]; 5883 PetscInt o = coneO[p]; 5884 PetscInt dof, off, d; 5885 const PetscScalar *varr; 5886 5887 if ((cp < pStart) || (cp >= pEnd)) continue; 5888 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5889 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5890 varr = &vArray[off]; 5891 if (o >= 0) { 5892 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5893 } else { 5894 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5895 } 5896 size += dof; 5897 } 5898 PetscCall(VecRestoreArrayRead(v, &vArray)); 5899 if (!*values) { 5900 if (csize) *csize = size; 5901 *values = array; 5902 } else { 5903 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5904 *csize = size; 5905 } 5906 PetscFunctionReturn(PETSC_SUCCESS); 5907 } 5908 5909 /* Compress out points not in the section */ 5910 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5911 { 5912 const PetscInt np = *numPoints; 5913 PetscInt pStart, pEnd, p, q; 5914 5915 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5916 for (p = 0, q = 0; p < np; ++p) { 5917 const PetscInt r = points[p * 2]; 5918 if ((r >= pStart) && (r < pEnd)) { 5919 points[q * 2] = r; 5920 points[q * 2 + 1] = points[p * 2 + 1]; 5921 ++q; 5922 } 5923 } 5924 *numPoints = q; 5925 return PETSC_SUCCESS; 5926 } 5927 5928 /* Compressed closure does not apply closure permutation */ 5929 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5930 { 5931 const PetscInt *cla = NULL; 5932 PetscInt np, *pts = NULL; 5933 5934 PetscFunctionBeginHot; 5935 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5936 if (!ornt && *clPoints) { 5937 PetscInt dof, off; 5938 5939 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5940 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5941 PetscCall(ISGetIndices(*clPoints, &cla)); 5942 np = dof / 2; 5943 pts = (PetscInt *)&cla[off]; 5944 } else { 5945 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 5946 PetscCall(CompressPoints_Private(section, &np, pts)); 5947 } 5948 *numPoints = np; 5949 *points = pts; 5950 *clp = cla; 5951 PetscFunctionReturn(PETSC_SUCCESS); 5952 } 5953 5954 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5955 { 5956 PetscFunctionBeginHot; 5957 if (!*clPoints) { 5958 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5959 } else { 5960 PetscCall(ISRestoreIndices(*clPoints, clp)); 5961 } 5962 *numPoints = 0; 5963 *points = NULL; 5964 *clSec = NULL; 5965 *clPoints = NULL; 5966 *clp = NULL; 5967 PetscFunctionReturn(PETSC_SUCCESS); 5968 } 5969 5970 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5971 { 5972 PetscInt offset = 0, p; 5973 const PetscInt **perms = NULL; 5974 const PetscScalar **flips = NULL; 5975 5976 PetscFunctionBeginHot; 5977 *size = 0; 5978 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5979 for (p = 0; p < numPoints; p++) { 5980 const PetscInt point = points[2 * p]; 5981 const PetscInt *perm = perms ? perms[p] : NULL; 5982 const PetscScalar *flip = flips ? flips[p] : NULL; 5983 PetscInt dof, off, d; 5984 const PetscScalar *varr; 5985 5986 PetscCall(PetscSectionGetDof(section, point, &dof)); 5987 PetscCall(PetscSectionGetOffset(section, point, &off)); 5988 varr = &vArray[off]; 5989 if (clperm) { 5990 if (perm) { 5991 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5992 } else { 5993 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5994 } 5995 if (flip) { 5996 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5997 } 5998 } else { 5999 if (perm) { 6000 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6001 } else { 6002 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6003 } 6004 if (flip) { 6005 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6006 } 6007 } 6008 offset += dof; 6009 } 6010 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6011 *size = offset; 6012 PetscFunctionReturn(PETSC_SUCCESS); 6013 } 6014 6015 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[]) 6016 { 6017 PetscInt offset = 0, f; 6018 6019 PetscFunctionBeginHot; 6020 *size = 0; 6021 for (f = 0; f < numFields; ++f) { 6022 PetscInt p; 6023 const PetscInt **perms = NULL; 6024 const PetscScalar **flips = NULL; 6025 6026 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6027 for (p = 0; p < numPoints; p++) { 6028 const PetscInt point = points[2 * p]; 6029 PetscInt fdof, foff, b; 6030 const PetscScalar *varr; 6031 const PetscInt *perm = perms ? perms[p] : NULL; 6032 const PetscScalar *flip = flips ? flips[p] : NULL; 6033 6034 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6035 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6036 varr = &vArray[foff]; 6037 if (clperm) { 6038 if (perm) { 6039 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6040 } else { 6041 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6042 } 6043 if (flip) { 6044 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6045 } 6046 } else { 6047 if (perm) { 6048 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6049 } else { 6050 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6051 } 6052 if (flip) { 6053 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6054 } 6055 } 6056 offset += fdof; 6057 } 6058 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6059 } 6060 *size = offset; 6061 PetscFunctionReturn(PETSC_SUCCESS); 6062 } 6063 6064 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6065 { 6066 PetscSection clSection; 6067 IS clPoints; 6068 PetscInt *points = NULL; 6069 const PetscInt *clp, *perm = NULL; 6070 PetscInt depth, numFields, numPoints, asize; 6071 6072 PetscFunctionBeginHot; 6073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6074 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6075 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6076 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6077 PetscCall(DMPlexGetDepth(dm, &depth)); 6078 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6079 if (depth == 1 && numFields < 2) { 6080 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6081 PetscFunctionReturn(PETSC_SUCCESS); 6082 } 6083 /* Get points */ 6084 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6085 /* Get sizes */ 6086 asize = 0; 6087 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6088 PetscInt dof; 6089 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6090 asize += dof; 6091 } 6092 if (values) { 6093 const PetscScalar *vArray; 6094 PetscInt size; 6095 6096 if (*values) { 6097 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); 6098 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6099 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6100 PetscCall(VecGetArrayRead(v, &vArray)); 6101 /* Get values */ 6102 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6103 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6104 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6105 /* Cleanup array */ 6106 PetscCall(VecRestoreArrayRead(v, &vArray)); 6107 } 6108 if (csize) *csize = asize; 6109 /* Cleanup points */ 6110 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6111 PetscFunctionReturn(PETSC_SUCCESS); 6112 } 6113 6114 /*@C 6115 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6116 6117 Not collective 6118 6119 Input Parameters: 6120 + dm - The `DM` 6121 . section - The section describing the layout in `v`, or `NULL` to use the default section 6122 . v - The local vector 6123 - point - The point in the `DM` 6124 6125 Input/Output Parameters: 6126 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6127 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6128 if the user provided `NULL`, it is a borrowed array and should not be freed 6129 6130 Level: intermediate 6131 6132 Notes: 6133 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6134 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6135 assembly function, and a user may already have allocated storage for this operation. 6136 6137 A typical use could be 6138 .vb 6139 values = NULL; 6140 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6141 for (cl = 0; cl < clSize; ++cl) { 6142 <Compute on closure> 6143 } 6144 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6145 .ve 6146 or 6147 .vb 6148 PetscMalloc1(clMaxSize, &values); 6149 for (p = pStart; p < pEnd; ++p) { 6150 clSize = clMaxSize; 6151 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6152 for (cl = 0; cl < clSize; ++cl) { 6153 <Compute on closure> 6154 } 6155 } 6156 PetscFree(values); 6157 .ve 6158 6159 Fortran Notes: 6160 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6161 6162 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6163 @*/ 6164 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6165 { 6166 PetscFunctionBeginHot; 6167 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6168 PetscFunctionReturn(PETSC_SUCCESS); 6169 } 6170 6171 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6172 { 6173 DMLabel depthLabel; 6174 PetscSection clSection; 6175 IS clPoints; 6176 PetscScalar *array; 6177 const PetscScalar *vArray; 6178 PetscInt *points = NULL; 6179 const PetscInt *clp, *perm = NULL; 6180 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6181 6182 PetscFunctionBeginHot; 6183 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6184 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6185 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6186 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6187 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6188 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6189 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6190 if (mdepth == 1 && numFields < 2) { 6191 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6192 PetscFunctionReturn(PETSC_SUCCESS); 6193 } 6194 /* Get points */ 6195 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6196 for (clsize = 0, p = 0; p < Np; p++) { 6197 PetscInt dof; 6198 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6199 clsize += dof; 6200 } 6201 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6202 /* Filter points */ 6203 for (p = 0; p < numPoints * 2; p += 2) { 6204 PetscInt dep; 6205 6206 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6207 if (dep != depth) continue; 6208 points[Np * 2 + 0] = points[p]; 6209 points[Np * 2 + 1] = points[p + 1]; 6210 ++Np; 6211 } 6212 /* Get array */ 6213 if (!values || !*values) { 6214 PetscInt asize = 0, dof; 6215 6216 for (p = 0; p < Np * 2; p += 2) { 6217 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6218 asize += dof; 6219 } 6220 if (!values) { 6221 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6222 if (csize) *csize = asize; 6223 PetscFunctionReturn(PETSC_SUCCESS); 6224 } 6225 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6226 } else { 6227 array = *values; 6228 } 6229 PetscCall(VecGetArrayRead(v, &vArray)); 6230 /* Get values */ 6231 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6232 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6233 /* Cleanup points */ 6234 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6235 /* Cleanup array */ 6236 PetscCall(VecRestoreArrayRead(v, &vArray)); 6237 if (!*values) { 6238 if (csize) *csize = size; 6239 *values = array; 6240 } else { 6241 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6242 *csize = size; 6243 } 6244 PetscFunctionReturn(PETSC_SUCCESS); 6245 } 6246 6247 /*@C 6248 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6249 6250 Not collective 6251 6252 Input Parameters: 6253 + dm - The `DM` 6254 . section - The section describing the layout in `v`, or `NULL` to use the default section 6255 . v - The local vector 6256 . point - The point in the `DM` 6257 . csize - The number of values in the closure, or `NULL` 6258 - values - The array of values, which is a borrowed array and should not be freed 6259 6260 Level: intermediate 6261 6262 Note: 6263 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6264 6265 Fortran Notes: 6266 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6267 6268 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6269 @*/ 6270 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6271 { 6272 PetscInt size = 0; 6273 6274 PetscFunctionBegin; 6275 /* Should work without recalculating size */ 6276 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6277 *values = NULL; 6278 PetscFunctionReturn(PETSC_SUCCESS); 6279 } 6280 6281 static inline void add(PetscScalar *x, PetscScalar y) 6282 { 6283 *x += y; 6284 } 6285 static inline void insert(PetscScalar *x, PetscScalar y) 6286 { 6287 *x = y; 6288 } 6289 6290 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[]) 6291 { 6292 PetscInt cdof; /* The number of constraints on this point */ 6293 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6294 PetscScalar *a; 6295 PetscInt off, cind = 0, k; 6296 6297 PetscFunctionBegin; 6298 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6299 PetscCall(PetscSectionGetOffset(section, point, &off)); 6300 a = &array[off]; 6301 if (!cdof || setBC) { 6302 if (clperm) { 6303 if (perm) { 6304 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6305 } else { 6306 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6307 } 6308 } else { 6309 if (perm) { 6310 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6311 } else { 6312 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6313 } 6314 } 6315 } else { 6316 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6317 if (clperm) { 6318 if (perm) { 6319 for (k = 0; k < dof; ++k) { 6320 if ((cind < cdof) && (k == cdofs[cind])) { 6321 ++cind; 6322 continue; 6323 } 6324 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6325 } 6326 } else { 6327 for (k = 0; k < dof; ++k) { 6328 if ((cind < cdof) && (k == cdofs[cind])) { 6329 ++cind; 6330 continue; 6331 } 6332 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6333 } 6334 } 6335 } else { 6336 if (perm) { 6337 for (k = 0; k < dof; ++k) { 6338 if ((cind < cdof) && (k == cdofs[cind])) { 6339 ++cind; 6340 continue; 6341 } 6342 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6343 } 6344 } else { 6345 for (k = 0; k < dof; ++k) { 6346 if ((cind < cdof) && (k == cdofs[cind])) { 6347 ++cind; 6348 continue; 6349 } 6350 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6351 } 6352 } 6353 } 6354 } 6355 PetscFunctionReturn(PETSC_SUCCESS); 6356 } 6357 6358 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[]) 6359 { 6360 PetscInt cdof; /* The number of constraints on this point */ 6361 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6362 PetscScalar *a; 6363 PetscInt off, cind = 0, k; 6364 6365 PetscFunctionBegin; 6366 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6367 PetscCall(PetscSectionGetOffset(section, point, &off)); 6368 a = &array[off]; 6369 if (cdof) { 6370 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6371 if (clperm) { 6372 if (perm) { 6373 for (k = 0; k < dof; ++k) { 6374 if ((cind < cdof) && (k == cdofs[cind])) { 6375 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6376 cind++; 6377 } 6378 } 6379 } else { 6380 for (k = 0; k < dof; ++k) { 6381 if ((cind < cdof) && (k == cdofs[cind])) { 6382 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6383 cind++; 6384 } 6385 } 6386 } 6387 } else { 6388 if (perm) { 6389 for (k = 0; k < dof; ++k) { 6390 if ((cind < cdof) && (k == cdofs[cind])) { 6391 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6392 cind++; 6393 } 6394 } 6395 } else { 6396 for (k = 0; k < dof; ++k) { 6397 if ((cind < cdof) && (k == cdofs[cind])) { 6398 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6399 cind++; 6400 } 6401 } 6402 } 6403 } 6404 } 6405 PetscFunctionReturn(PETSC_SUCCESS); 6406 } 6407 6408 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[]) 6409 { 6410 PetscScalar *a; 6411 PetscInt fdof, foff, fcdof, foffset = *offset; 6412 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6413 PetscInt cind = 0, b; 6414 6415 PetscFunctionBegin; 6416 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6417 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6418 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6419 a = &array[foff]; 6420 if (!fcdof || setBC) { 6421 if (clperm) { 6422 if (perm) { 6423 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6424 } else { 6425 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6426 } 6427 } else { 6428 if (perm) { 6429 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6430 } else { 6431 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6432 } 6433 } 6434 } else { 6435 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6436 if (clperm) { 6437 if (perm) { 6438 for (b = 0; b < fdof; b++) { 6439 if ((cind < fcdof) && (b == fcdofs[cind])) { 6440 ++cind; 6441 continue; 6442 } 6443 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6444 } 6445 } else { 6446 for (b = 0; b < fdof; b++) { 6447 if ((cind < fcdof) && (b == fcdofs[cind])) { 6448 ++cind; 6449 continue; 6450 } 6451 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6452 } 6453 } 6454 } else { 6455 if (perm) { 6456 for (b = 0; b < fdof; b++) { 6457 if ((cind < fcdof) && (b == fcdofs[cind])) { 6458 ++cind; 6459 continue; 6460 } 6461 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6462 } 6463 } else { 6464 for (b = 0; b < fdof; b++) { 6465 if ((cind < fcdof) && (b == fcdofs[cind])) { 6466 ++cind; 6467 continue; 6468 } 6469 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6470 } 6471 } 6472 } 6473 } 6474 *offset += fdof; 6475 PetscFunctionReturn(PETSC_SUCCESS); 6476 } 6477 6478 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[]) 6479 { 6480 PetscScalar *a; 6481 PetscInt fdof, foff, fcdof, foffset = *offset; 6482 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6483 PetscInt Nc, cind = 0, ncind = 0, b; 6484 PetscBool ncSet, fcSet; 6485 6486 PetscFunctionBegin; 6487 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6488 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6489 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6490 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6491 a = &array[foff]; 6492 if (fcdof) { 6493 /* We just override fcdof and fcdofs with Ncc and comps */ 6494 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6495 if (clperm) { 6496 if (perm) { 6497 if (comps) { 6498 for (b = 0; b < fdof; b++) { 6499 ncSet = fcSet = PETSC_FALSE; 6500 if (b % Nc == comps[ncind]) { 6501 ncind = (ncind + 1) % Ncc; 6502 ncSet = PETSC_TRUE; 6503 } 6504 if ((cind < fcdof) && (b == fcdofs[cind])) { 6505 ++cind; 6506 fcSet = PETSC_TRUE; 6507 } 6508 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6509 } 6510 } else { 6511 for (b = 0; b < fdof; b++) { 6512 if ((cind < fcdof) && (b == fcdofs[cind])) { 6513 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6514 ++cind; 6515 } 6516 } 6517 } 6518 } else { 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[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6531 } 6532 } else { 6533 for (b = 0; b < fdof; b++) { 6534 if ((cind < fcdof) && (b == fcdofs[cind])) { 6535 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6536 ++cind; 6537 } 6538 } 6539 } 6540 } 6541 } else { 6542 if (perm) { 6543 if (comps) { 6544 for (b = 0; b < fdof; b++) { 6545 ncSet = fcSet = PETSC_FALSE; 6546 if (b % Nc == comps[ncind]) { 6547 ncind = (ncind + 1) % Ncc; 6548 ncSet = PETSC_TRUE; 6549 } 6550 if ((cind < fcdof) && (b == fcdofs[cind])) { 6551 ++cind; 6552 fcSet = PETSC_TRUE; 6553 } 6554 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6555 } 6556 } else { 6557 for (b = 0; b < fdof; b++) { 6558 if ((cind < fcdof) && (b == fcdofs[cind])) { 6559 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6560 ++cind; 6561 } 6562 } 6563 } 6564 } else { 6565 if (comps) { 6566 for (b = 0; b < fdof; b++) { 6567 ncSet = fcSet = PETSC_FALSE; 6568 if (b % Nc == comps[ncind]) { 6569 ncind = (ncind + 1) % Ncc; 6570 ncSet = PETSC_TRUE; 6571 } 6572 if ((cind < fcdof) && (b == fcdofs[cind])) { 6573 ++cind; 6574 fcSet = PETSC_TRUE; 6575 } 6576 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6577 } 6578 } else { 6579 for (b = 0; b < fdof; b++) { 6580 if ((cind < fcdof) && (b == fcdofs[cind])) { 6581 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6582 ++cind; 6583 } 6584 } 6585 } 6586 } 6587 } 6588 } 6589 *offset += fdof; 6590 PetscFunctionReturn(PETSC_SUCCESS); 6591 } 6592 6593 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6594 { 6595 PetscScalar *array; 6596 const PetscInt *cone, *coneO; 6597 PetscInt pStart, pEnd, p, numPoints, off, dof; 6598 6599 PetscFunctionBeginHot; 6600 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6601 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6602 PetscCall(DMPlexGetCone(dm, point, &cone)); 6603 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6604 PetscCall(VecGetArray(v, &array)); 6605 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6606 const PetscInt cp = !p ? point : cone[p - 1]; 6607 const PetscInt o = !p ? 0 : coneO[p - 1]; 6608 6609 if ((cp < pStart) || (cp >= pEnd)) { 6610 dof = 0; 6611 continue; 6612 } 6613 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6614 /* ADD_VALUES */ 6615 { 6616 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6617 PetscScalar *a; 6618 PetscInt cdof, coff, cind = 0, k; 6619 6620 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6621 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6622 a = &array[coff]; 6623 if (!cdof) { 6624 if (o >= 0) { 6625 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6626 } else { 6627 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6628 } 6629 } else { 6630 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6631 if (o >= 0) { 6632 for (k = 0; k < dof; ++k) { 6633 if ((cind < cdof) && (k == cdofs[cind])) { 6634 ++cind; 6635 continue; 6636 } 6637 a[k] += values[off + k]; 6638 } 6639 } else { 6640 for (k = 0; k < dof; ++k) { 6641 if ((cind < cdof) && (k == cdofs[cind])) { 6642 ++cind; 6643 continue; 6644 } 6645 a[k] += values[off + dof - k - 1]; 6646 } 6647 } 6648 } 6649 } 6650 } 6651 PetscCall(VecRestoreArray(v, &array)); 6652 PetscFunctionReturn(PETSC_SUCCESS); 6653 } 6654 6655 /*@C 6656 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6657 6658 Not collective 6659 6660 Input Parameters: 6661 + dm - The `DM` 6662 . section - The section describing the layout in `v`, or `NULL` to use the default section 6663 . v - The local vector 6664 . point - The point in the `DM` 6665 . values - The array of values 6666 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6667 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6668 6669 Level: intermediate 6670 6671 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6672 @*/ 6673 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6674 { 6675 PetscSection clSection; 6676 IS clPoints; 6677 PetscScalar *array; 6678 PetscInt *points = NULL; 6679 const PetscInt *clp, *clperm = NULL; 6680 PetscInt depth, numFields, numPoints, p, clsize; 6681 6682 PetscFunctionBeginHot; 6683 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6684 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6685 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6686 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6687 PetscCall(DMPlexGetDepth(dm, &depth)); 6688 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6689 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6690 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6691 PetscFunctionReturn(PETSC_SUCCESS); 6692 } 6693 /* Get points */ 6694 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6695 for (clsize = 0, p = 0; p < numPoints; p++) { 6696 PetscInt dof; 6697 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6698 clsize += dof; 6699 } 6700 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6701 /* Get array */ 6702 PetscCall(VecGetArray(v, &array)); 6703 /* Get values */ 6704 if (numFields > 0) { 6705 PetscInt offset = 0, f; 6706 for (f = 0; f < numFields; ++f) { 6707 const PetscInt **perms = NULL; 6708 const PetscScalar **flips = NULL; 6709 6710 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6711 switch (mode) { 6712 case INSERT_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, insert, PETSC_FALSE, clperm, values, &offset, array)); 6718 } 6719 break; 6720 case INSERT_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, insert, PETSC_TRUE, clperm, values, &offset, array)); 6726 } 6727 break; 6728 case INSERT_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, insert, clperm, values, &offset, array)); 6734 } 6735 break; 6736 case ADD_VALUES: 6737 for (p = 0; p < numPoints; p++) { 6738 const PetscInt point = points[2 * p]; 6739 const PetscInt *perm = perms ? perms[p] : NULL; 6740 const PetscScalar *flip = flips ? flips[p] : NULL; 6741 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6742 } 6743 break; 6744 case ADD_ALL_VALUES: 6745 for (p = 0; p < numPoints; p++) { 6746 const PetscInt point = points[2 * p]; 6747 const PetscInt *perm = perms ? perms[p] : NULL; 6748 const PetscScalar *flip = flips ? flips[p] : NULL; 6749 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6750 } 6751 break; 6752 case ADD_BC_VALUES: 6753 for (p = 0; p < numPoints; p++) { 6754 const PetscInt point = points[2 * p]; 6755 const PetscInt *perm = perms ? perms[p] : NULL; 6756 const PetscScalar *flip = flips ? flips[p] : NULL; 6757 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6758 } 6759 break; 6760 default: 6761 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6762 } 6763 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6764 } 6765 } else { 6766 PetscInt dof, off; 6767 const PetscInt **perms = NULL; 6768 const PetscScalar **flips = NULL; 6769 6770 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6771 switch (mode) { 6772 case INSERT_VALUES: 6773 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6774 const PetscInt point = points[2 * p]; 6775 const PetscInt *perm = perms ? perms[p] : NULL; 6776 const PetscScalar *flip = flips ? flips[p] : NULL; 6777 PetscCall(PetscSectionGetDof(section, point, &dof)); 6778 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6779 } 6780 break; 6781 case INSERT_ALL_VALUES: 6782 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6783 const PetscInt point = points[2 * p]; 6784 const PetscInt *perm = perms ? perms[p] : NULL; 6785 const PetscScalar *flip = flips ? flips[p] : NULL; 6786 PetscCall(PetscSectionGetDof(section, point, &dof)); 6787 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6788 } 6789 break; 6790 case INSERT_BC_VALUES: 6791 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6792 const PetscInt point = points[2 * p]; 6793 const PetscInt *perm = perms ? perms[p] : NULL; 6794 const PetscScalar *flip = flips ? flips[p] : NULL; 6795 PetscCall(PetscSectionGetDof(section, point, &dof)); 6796 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6797 } 6798 break; 6799 case ADD_VALUES: 6800 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6801 const PetscInt point = points[2 * p]; 6802 const PetscInt *perm = perms ? perms[p] : NULL; 6803 const PetscScalar *flip = flips ? flips[p] : NULL; 6804 PetscCall(PetscSectionGetDof(section, point, &dof)); 6805 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6806 } 6807 break; 6808 case ADD_ALL_VALUES: 6809 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6810 const PetscInt point = points[2 * p]; 6811 const PetscInt *perm = perms ? perms[p] : NULL; 6812 const PetscScalar *flip = flips ? flips[p] : NULL; 6813 PetscCall(PetscSectionGetDof(section, point, &dof)); 6814 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6815 } 6816 break; 6817 case ADD_BC_VALUES: 6818 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6819 const PetscInt point = points[2 * p]; 6820 const PetscInt *perm = perms ? perms[p] : NULL; 6821 const PetscScalar *flip = flips ? flips[p] : NULL; 6822 PetscCall(PetscSectionGetDof(section, point, &dof)); 6823 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6824 } 6825 break; 6826 default: 6827 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6828 } 6829 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6830 } 6831 /* Cleanup points */ 6832 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6833 /* Cleanup array */ 6834 PetscCall(VecRestoreArray(v, &array)); 6835 PetscFunctionReturn(PETSC_SUCCESS); 6836 } 6837 6838 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6839 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6840 { 6841 PetscFunctionBegin; 6842 *contains = PETSC_TRUE; 6843 if (label) { 6844 PetscInt fdof; 6845 6846 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6847 if (!*contains) { 6848 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6849 *offset += fdof; 6850 PetscFunctionReturn(PETSC_SUCCESS); 6851 } 6852 } 6853 PetscFunctionReturn(PETSC_SUCCESS); 6854 } 6855 6856 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6857 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) 6858 { 6859 PetscSection clSection; 6860 IS clPoints; 6861 PetscScalar *array; 6862 PetscInt *points = NULL; 6863 const PetscInt *clp; 6864 PetscInt numFields, numPoints, p; 6865 PetscInt offset = 0, f; 6866 6867 PetscFunctionBeginHot; 6868 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6869 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6870 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6871 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6872 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6873 /* Get points */ 6874 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6875 /* Get array */ 6876 PetscCall(VecGetArray(v, &array)); 6877 /* Get values */ 6878 for (f = 0; f < numFields; ++f) { 6879 const PetscInt **perms = NULL; 6880 const PetscScalar **flips = NULL; 6881 PetscBool contains; 6882 6883 if (!fieldActive[f]) { 6884 for (p = 0; p < numPoints * 2; p += 2) { 6885 PetscInt fdof; 6886 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6887 offset += fdof; 6888 } 6889 continue; 6890 } 6891 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6892 switch (mode) { 6893 case INSERT_VALUES: 6894 for (p = 0; p < numPoints; p++) { 6895 const PetscInt point = points[2 * p]; 6896 const PetscInt *perm = perms ? perms[p] : NULL; 6897 const PetscScalar *flip = flips ? flips[p] : NULL; 6898 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6899 if (!contains) continue; 6900 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6901 } 6902 break; 6903 case INSERT_ALL_VALUES: 6904 for (p = 0; p < numPoints; p++) { 6905 const PetscInt point = points[2 * p]; 6906 const PetscInt *perm = perms ? perms[p] : NULL; 6907 const PetscScalar *flip = flips ? flips[p] : NULL; 6908 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6909 if (!contains) continue; 6910 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6911 } 6912 break; 6913 case INSERT_BC_VALUES: 6914 for (p = 0; p < numPoints; p++) { 6915 const PetscInt point = points[2 * p]; 6916 const PetscInt *perm = perms ? perms[p] : NULL; 6917 const PetscScalar *flip = flips ? flips[p] : NULL; 6918 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6919 if (!contains) continue; 6920 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6921 } 6922 break; 6923 case ADD_VALUES: 6924 for (p = 0; p < numPoints; p++) { 6925 const PetscInt point = points[2 * p]; 6926 const PetscInt *perm = perms ? perms[p] : NULL; 6927 const PetscScalar *flip = flips ? flips[p] : NULL; 6928 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6929 if (!contains) continue; 6930 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6931 } 6932 break; 6933 case ADD_ALL_VALUES: 6934 for (p = 0; p < numPoints; p++) { 6935 const PetscInt point = points[2 * p]; 6936 const PetscInt *perm = perms ? perms[p] : NULL; 6937 const PetscScalar *flip = flips ? flips[p] : NULL; 6938 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6939 if (!contains) continue; 6940 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6941 } 6942 break; 6943 default: 6944 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6945 } 6946 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6947 } 6948 /* Cleanup points */ 6949 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6950 /* Cleanup array */ 6951 PetscCall(VecRestoreArray(v, &array)); 6952 PetscFunctionReturn(PETSC_SUCCESS); 6953 } 6954 6955 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6956 { 6957 PetscMPIInt rank; 6958 PetscInt i, j; 6959 6960 PetscFunctionBegin; 6961 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6962 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6963 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6964 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6965 numCIndices = numCIndices ? numCIndices : numRIndices; 6966 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 6967 for (i = 0; i < numRIndices; i++) { 6968 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6969 for (j = 0; j < numCIndices; j++) { 6970 #if defined(PETSC_USE_COMPLEX) 6971 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6972 #else 6973 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6974 #endif 6975 } 6976 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6977 } 6978 PetscFunctionReturn(PETSC_SUCCESS); 6979 } 6980 6981 /* 6982 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6983 6984 Input Parameters: 6985 + section - The section for this data layout 6986 . islocal - Is the section (and thus indices being requested) local or global? 6987 . point - The point contributing dofs with these indices 6988 . off - The global offset of this point 6989 . loff - The local offset of each field 6990 . setBC - The flag determining whether to include indices of boundary values 6991 . perm - A permutation of the dofs on this point, or NULL 6992 - indperm - A permutation of the entire indices array, or NULL 6993 6994 Output Parameter: 6995 . indices - Indices for dofs on this point 6996 6997 Level: developer 6998 6999 Note: The indices could be local or global, depending on the value of 'off'. 7000 */ 7001 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7002 { 7003 PetscInt dof; /* The number of unknowns on this point */ 7004 PetscInt cdof; /* The number of constraints on this point */ 7005 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7006 PetscInt cind = 0, k; 7007 7008 PetscFunctionBegin; 7009 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7010 PetscCall(PetscSectionGetDof(section, point, &dof)); 7011 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7012 if (!cdof || setBC) { 7013 for (k = 0; k < dof; ++k) { 7014 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7015 const PetscInt ind = indperm ? indperm[preind] : preind; 7016 7017 indices[ind] = off + k; 7018 } 7019 } else { 7020 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7021 for (k = 0; k < dof; ++k) { 7022 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7023 const PetscInt ind = indperm ? indperm[preind] : preind; 7024 7025 if ((cind < cdof) && (k == cdofs[cind])) { 7026 /* Insert check for returning constrained indices */ 7027 indices[ind] = -(off + k + 1); 7028 ++cind; 7029 } else { 7030 indices[ind] = off + k - (islocal ? 0 : cind); 7031 } 7032 } 7033 } 7034 *loff += dof; 7035 PetscFunctionReturn(PETSC_SUCCESS); 7036 } 7037 7038 /* 7039 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7040 7041 Input Parameters: 7042 + section - a section (global or local) 7043 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7044 . point - point within section 7045 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7046 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7047 . setBC - identify constrained (boundary condition) points via involution. 7048 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7049 . permsoff - offset 7050 - indperm - index permutation 7051 7052 Output Parameter: 7053 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7054 . indices - array to hold indices (as defined by section) of each dof associated with point 7055 7056 Notes: 7057 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7058 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7059 in the local vector. 7060 7061 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7062 significant). It is invalid to call with a global section and setBC=true. 7063 7064 Developer Note: 7065 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7066 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7067 offset could be obtained from the section instead of passing it explicitly as we do now. 7068 7069 Example: 7070 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7071 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7072 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7073 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. 7074 7075 Level: developer 7076 */ 7077 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[]) 7078 { 7079 PetscInt numFields, foff, f; 7080 7081 PetscFunctionBegin; 7082 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7083 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7084 for (f = 0, foff = 0; f < numFields; ++f) { 7085 PetscInt fdof, cfdof; 7086 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7087 PetscInt cind = 0, b; 7088 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7089 7090 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7091 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7092 if (!cfdof || setBC) { 7093 for (b = 0; b < fdof; ++b) { 7094 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7095 const PetscInt ind = indperm ? indperm[preind] : preind; 7096 7097 indices[ind] = off + foff + b; 7098 } 7099 } else { 7100 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7101 for (b = 0; b < fdof; ++b) { 7102 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7103 const PetscInt ind = indperm ? indperm[preind] : preind; 7104 7105 if ((cind < cfdof) && (b == fcdofs[cind])) { 7106 indices[ind] = -(off + foff + b + 1); 7107 ++cind; 7108 } else { 7109 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7110 } 7111 } 7112 } 7113 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7114 foffs[f] += fdof; 7115 } 7116 PetscFunctionReturn(PETSC_SUCCESS); 7117 } 7118 7119 /* 7120 This version believes the globalSection offsets for each field, rather than just the point offset 7121 7122 . foffs - The offset into 'indices' for each field, since it is segregated by field 7123 7124 Notes: 7125 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7126 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7127 */ 7128 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7129 { 7130 PetscInt numFields, foff, f; 7131 7132 PetscFunctionBegin; 7133 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7134 for (f = 0; f < numFields; ++f) { 7135 PetscInt fdof, cfdof; 7136 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7137 PetscInt cind = 0, b; 7138 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7139 7140 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7141 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7142 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7143 if (!cfdof) { 7144 for (b = 0; b < fdof; ++b) { 7145 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7146 const PetscInt ind = indperm ? indperm[preind] : preind; 7147 7148 indices[ind] = foff + b; 7149 } 7150 } else { 7151 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7152 for (b = 0; b < fdof; ++b) { 7153 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7154 const PetscInt ind = indperm ? indperm[preind] : preind; 7155 7156 if ((cind < cfdof) && (b == fcdofs[cind])) { 7157 indices[ind] = -(foff + b + 1); 7158 ++cind; 7159 } else { 7160 indices[ind] = foff + b - cind; 7161 } 7162 } 7163 } 7164 foffs[f] += fdof; 7165 } 7166 PetscFunctionReturn(PETSC_SUCCESS); 7167 } 7168 7169 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) 7170 { 7171 Mat cMat; 7172 PetscSection aSec, cSec; 7173 IS aIS; 7174 PetscInt aStart = -1, aEnd = -1; 7175 const PetscInt *anchors; 7176 PetscInt numFields, f, p, q, newP = 0; 7177 PetscInt newNumPoints = 0, newNumIndices = 0; 7178 PetscInt *newPoints, *indices, *newIndices; 7179 PetscInt maxAnchor, maxDof; 7180 PetscInt newOffsets[32]; 7181 PetscInt *pointMatOffsets[32]; 7182 PetscInt *newPointOffsets[32]; 7183 PetscScalar *pointMat[32]; 7184 PetscScalar *newValues = NULL, *tmpValues; 7185 PetscBool anyConstrained = PETSC_FALSE; 7186 7187 PetscFunctionBegin; 7188 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7189 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7190 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7191 7192 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7193 /* if there are point-to-point constraints */ 7194 if (aSec) { 7195 PetscCall(PetscArrayzero(newOffsets, 32)); 7196 PetscCall(ISGetIndices(aIS, &anchors)); 7197 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7198 /* figure out how many points are going to be in the new element matrix 7199 * (we allow double counting, because it's all just going to be summed 7200 * into the global matrix anyway) */ 7201 for (p = 0; p < 2 * numPoints; p += 2) { 7202 PetscInt b = points[p]; 7203 PetscInt bDof = 0, bSecDof; 7204 7205 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7206 if (!bSecDof) continue; 7207 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7208 if (bDof) { 7209 /* this point is constrained */ 7210 /* it is going to be replaced by its anchors */ 7211 PetscInt bOff, q; 7212 7213 anyConstrained = PETSC_TRUE; 7214 newNumPoints += bDof; 7215 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7216 for (q = 0; q < bDof; q++) { 7217 PetscInt a = anchors[bOff + q]; 7218 PetscInt aDof; 7219 7220 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7221 newNumIndices += aDof; 7222 for (f = 0; f < numFields; ++f) { 7223 PetscInt fDof; 7224 7225 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7226 newOffsets[f + 1] += fDof; 7227 } 7228 } 7229 } else { 7230 /* this point is not constrained */ 7231 newNumPoints++; 7232 newNumIndices += bSecDof; 7233 for (f = 0; f < numFields; ++f) { 7234 PetscInt fDof; 7235 7236 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7237 newOffsets[f + 1] += fDof; 7238 } 7239 } 7240 } 7241 } 7242 if (!anyConstrained) { 7243 if (outNumPoints) *outNumPoints = 0; 7244 if (outNumIndices) *outNumIndices = 0; 7245 if (outPoints) *outPoints = NULL; 7246 if (outValues) *outValues = NULL; 7247 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7248 PetscFunctionReturn(PETSC_SUCCESS); 7249 } 7250 7251 if (outNumPoints) *outNumPoints = newNumPoints; 7252 if (outNumIndices) *outNumIndices = newNumIndices; 7253 7254 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7255 7256 if (!outPoints && !outValues) { 7257 if (offsets) { 7258 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7259 } 7260 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7261 PetscFunctionReturn(PETSC_SUCCESS); 7262 } 7263 7264 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7265 7266 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7267 7268 /* workspaces */ 7269 if (numFields) { 7270 for (f = 0; f < numFields; f++) { 7271 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7272 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7273 } 7274 } else { 7275 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7276 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7277 } 7278 7279 /* get workspaces for the point-to-point matrices */ 7280 if (numFields) { 7281 PetscInt totalOffset, totalMatOffset; 7282 7283 for (p = 0; p < numPoints; p++) { 7284 PetscInt b = points[2 * p]; 7285 PetscInt bDof = 0, bSecDof; 7286 7287 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7288 if (!bSecDof) { 7289 for (f = 0; f < numFields; f++) { 7290 newPointOffsets[f][p + 1] = 0; 7291 pointMatOffsets[f][p + 1] = 0; 7292 } 7293 continue; 7294 } 7295 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7296 if (bDof) { 7297 for (f = 0; f < numFields; f++) { 7298 PetscInt fDof, q, bOff, allFDof = 0; 7299 7300 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7301 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7302 for (q = 0; q < bDof; q++) { 7303 PetscInt a = anchors[bOff + q]; 7304 PetscInt aFDof; 7305 7306 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7307 allFDof += aFDof; 7308 } 7309 newPointOffsets[f][p + 1] = allFDof; 7310 pointMatOffsets[f][p + 1] = fDof * allFDof; 7311 } 7312 } else { 7313 for (f = 0; f < numFields; f++) { 7314 PetscInt fDof; 7315 7316 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7317 newPointOffsets[f][p + 1] = fDof; 7318 pointMatOffsets[f][p + 1] = 0; 7319 } 7320 } 7321 } 7322 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7323 newPointOffsets[f][0] = totalOffset; 7324 pointMatOffsets[f][0] = totalMatOffset; 7325 for (p = 0; p < numPoints; p++) { 7326 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7327 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7328 } 7329 totalOffset = newPointOffsets[f][numPoints]; 7330 totalMatOffset = pointMatOffsets[f][numPoints]; 7331 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7332 } 7333 } else { 7334 for (p = 0; p < numPoints; p++) { 7335 PetscInt b = points[2 * p]; 7336 PetscInt bDof = 0, bSecDof; 7337 7338 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7339 if (!bSecDof) { 7340 newPointOffsets[0][p + 1] = 0; 7341 pointMatOffsets[0][p + 1] = 0; 7342 continue; 7343 } 7344 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7345 if (bDof) { 7346 PetscInt bOff, q, allDof = 0; 7347 7348 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7349 for (q = 0; q < bDof; q++) { 7350 PetscInt a = anchors[bOff + q], aDof; 7351 7352 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7353 allDof += aDof; 7354 } 7355 newPointOffsets[0][p + 1] = allDof; 7356 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7357 } else { 7358 newPointOffsets[0][p + 1] = bSecDof; 7359 pointMatOffsets[0][p + 1] = 0; 7360 } 7361 } 7362 newPointOffsets[0][0] = 0; 7363 pointMatOffsets[0][0] = 0; 7364 for (p = 0; p < numPoints; p++) { 7365 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7366 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7367 } 7368 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7369 } 7370 7371 /* output arrays */ 7372 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7373 7374 /* get the point-to-point matrices; construct newPoints */ 7375 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7376 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7377 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7378 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7379 if (numFields) { 7380 for (p = 0, newP = 0; p < numPoints; p++) { 7381 PetscInt b = points[2 * p]; 7382 PetscInt o = points[2 * p + 1]; 7383 PetscInt bDof = 0, bSecDof; 7384 7385 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7386 if (!bSecDof) continue; 7387 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7388 if (bDof) { 7389 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7390 7391 fStart[0] = 0; 7392 fEnd[0] = 0; 7393 for (f = 0; f < numFields; f++) { 7394 PetscInt fDof; 7395 7396 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7397 fStart[f + 1] = fStart[f] + fDof; 7398 fEnd[f + 1] = fStart[f + 1]; 7399 } 7400 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7401 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7402 7403 fAnchorStart[0] = 0; 7404 fAnchorEnd[0] = 0; 7405 for (f = 0; f < numFields; f++) { 7406 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7407 7408 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7409 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7410 } 7411 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7412 for (q = 0; q < bDof; q++) { 7413 PetscInt a = anchors[bOff + q], aOff; 7414 7415 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7416 newPoints[2 * (newP + q)] = a; 7417 newPoints[2 * (newP + q) + 1] = 0; 7418 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7419 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7420 } 7421 newP += bDof; 7422 7423 if (outValues) { 7424 /* get the point-to-point submatrix */ 7425 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])); 7426 } 7427 } else { 7428 newPoints[2 * newP] = b; 7429 newPoints[2 * newP + 1] = o; 7430 newP++; 7431 } 7432 } 7433 } else { 7434 for (p = 0; p < numPoints; p++) { 7435 PetscInt b = points[2 * p]; 7436 PetscInt o = points[2 * p + 1]; 7437 PetscInt bDof = 0, bSecDof; 7438 7439 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7440 if (!bSecDof) continue; 7441 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7442 if (bDof) { 7443 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7444 7445 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7446 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7447 7448 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7449 for (q = 0; q < bDof; q++) { 7450 PetscInt a = anchors[bOff + q], aOff; 7451 7452 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7453 7454 newPoints[2 * (newP + q)] = a; 7455 newPoints[2 * (newP + q) + 1] = 0; 7456 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7457 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7458 } 7459 newP += bDof; 7460 7461 /* get the point-to-point submatrix */ 7462 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7463 } else { 7464 newPoints[2 * newP] = b; 7465 newPoints[2 * newP + 1] = o; 7466 newP++; 7467 } 7468 } 7469 } 7470 7471 if (outValues) { 7472 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7473 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7474 /* multiply constraints on the right */ 7475 if (numFields) { 7476 for (f = 0; f < numFields; f++) { 7477 PetscInt oldOff = offsets[f]; 7478 7479 for (p = 0; p < numPoints; p++) { 7480 PetscInt cStart = newPointOffsets[f][p]; 7481 PetscInt b = points[2 * p]; 7482 PetscInt c, r, k; 7483 PetscInt dof; 7484 7485 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7486 if (!dof) continue; 7487 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7488 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7489 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7490 7491 for (r = 0; r < numIndices; r++) { 7492 for (c = 0; c < nCols; c++) { 7493 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7494 } 7495 } 7496 } else { 7497 /* copy this column as is */ 7498 for (r = 0; r < numIndices; r++) { 7499 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7500 } 7501 } 7502 oldOff += dof; 7503 } 7504 } 7505 } else { 7506 PetscInt oldOff = 0; 7507 for (p = 0; p < numPoints; p++) { 7508 PetscInt cStart = newPointOffsets[0][p]; 7509 PetscInt b = points[2 * p]; 7510 PetscInt c, r, k; 7511 PetscInt dof; 7512 7513 PetscCall(PetscSectionGetDof(section, b, &dof)); 7514 if (!dof) continue; 7515 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7516 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7517 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7518 7519 for (r = 0; r < numIndices; r++) { 7520 for (c = 0; c < nCols; c++) { 7521 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7522 } 7523 } 7524 } else { 7525 /* copy this column as is */ 7526 for (r = 0; r < numIndices; r++) { 7527 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7528 } 7529 } 7530 oldOff += dof; 7531 } 7532 } 7533 7534 if (multiplyLeft) { 7535 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7536 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7537 /* multiply constraints transpose on the left */ 7538 if (numFields) { 7539 for (f = 0; f < numFields; f++) { 7540 PetscInt oldOff = offsets[f]; 7541 7542 for (p = 0; p < numPoints; p++) { 7543 PetscInt rStart = newPointOffsets[f][p]; 7544 PetscInt b = points[2 * p]; 7545 PetscInt c, r, k; 7546 PetscInt dof; 7547 7548 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7549 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7550 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7551 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7552 7553 for (r = 0; r < nRows; r++) { 7554 for (c = 0; c < newNumIndices; c++) { 7555 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7556 } 7557 } 7558 } else { 7559 /* copy this row as is */ 7560 for (r = 0; r < dof; r++) { 7561 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7562 } 7563 } 7564 oldOff += dof; 7565 } 7566 } 7567 } else { 7568 PetscInt oldOff = 0; 7569 7570 for (p = 0; p < numPoints; p++) { 7571 PetscInt rStart = newPointOffsets[0][p]; 7572 PetscInt b = points[2 * p]; 7573 PetscInt c, r, k; 7574 PetscInt dof; 7575 7576 PetscCall(PetscSectionGetDof(section, b, &dof)); 7577 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7578 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7579 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7580 7581 for (r = 0; r < nRows; r++) { 7582 for (c = 0; c < newNumIndices; c++) { 7583 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7584 } 7585 } 7586 } else { 7587 /* copy this row as is */ 7588 for (r = 0; r < dof; r++) { 7589 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7590 } 7591 } 7592 oldOff += dof; 7593 } 7594 } 7595 7596 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7597 } else { 7598 newValues = tmpValues; 7599 } 7600 } 7601 7602 /* clean up */ 7603 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7604 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7605 7606 if (numFields) { 7607 for (f = 0; f < numFields; f++) { 7608 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7609 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7610 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7611 } 7612 } else { 7613 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7614 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7615 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7616 } 7617 PetscCall(ISRestoreIndices(aIS, &anchors)); 7618 7619 /* output */ 7620 if (outPoints) { 7621 *outPoints = newPoints; 7622 } else { 7623 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7624 } 7625 if (outValues) *outValues = newValues; 7626 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7627 PetscFunctionReturn(PETSC_SUCCESS); 7628 } 7629 7630 /*@C 7631 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7632 7633 Not collective 7634 7635 Input Parameters: 7636 + dm - The `DM` 7637 . section - The `PetscSection` describing the points (a local section) 7638 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7639 . point - The point defining the closure 7640 - useClPerm - Use the closure point permutation if available 7641 7642 Output Parameters: 7643 + numIndices - The number of dof indices in the closure of point with the input sections 7644 . indices - The dof indices 7645 . outOffsets - Array to write the field offsets into, or `NULL` 7646 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7647 7648 Level: advanced 7649 7650 Notes: 7651 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7652 7653 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7654 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7655 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7656 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7657 indices (with the above semantics) are implied. 7658 7659 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7660 `PetscSection`, `DMGetGlobalSection()` 7661 @*/ 7662 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7663 { 7664 /* Closure ordering */ 7665 PetscSection clSection; 7666 IS clPoints; 7667 const PetscInt *clp; 7668 PetscInt *points; 7669 const PetscInt *clperm = NULL; 7670 /* Dof permutation and sign flips */ 7671 const PetscInt **perms[32] = {NULL}; 7672 const PetscScalar **flips[32] = {NULL}; 7673 PetscScalar *valCopy = NULL; 7674 /* Hanging node constraints */ 7675 PetscInt *pointsC = NULL; 7676 PetscScalar *valuesC = NULL; 7677 PetscInt NclC, NiC; 7678 7679 PetscInt *idx; 7680 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7681 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7682 7683 PetscFunctionBeginHot; 7684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7685 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7686 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7687 if (numIndices) PetscAssertPointer(numIndices, 6); 7688 if (indices) PetscAssertPointer(indices, 7); 7689 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7690 if (values) PetscAssertPointer(values, 9); 7691 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7692 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7693 PetscCall(PetscArrayzero(offsets, 32)); 7694 /* 1) Get points in closure */ 7695 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7696 if (useClPerm) { 7697 PetscInt depth, clsize; 7698 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7699 for (clsize = 0, p = 0; p < Ncl; p++) { 7700 PetscInt dof; 7701 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7702 clsize += dof; 7703 } 7704 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7705 } 7706 /* 2) Get number of indices on these points and field offsets from section */ 7707 for (p = 0; p < Ncl * 2; p += 2) { 7708 PetscInt dof, fdof; 7709 7710 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7711 for (f = 0; f < Nf; ++f) { 7712 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7713 offsets[f + 1] += fdof; 7714 } 7715 Ni += dof; 7716 } 7717 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7718 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7719 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7720 for (f = 0; f < PetscMax(1, Nf); ++f) { 7721 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7722 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7723 /* may need to apply sign changes to the element matrix */ 7724 if (values && flips[f]) { 7725 PetscInt foffset = offsets[f]; 7726 7727 for (p = 0; p < Ncl; ++p) { 7728 PetscInt pnt = points[2 * p], fdof; 7729 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7730 7731 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7732 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7733 if (flip) { 7734 PetscInt i, j, k; 7735 7736 if (!valCopy) { 7737 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7738 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7739 *values = valCopy; 7740 } 7741 for (i = 0; i < fdof; ++i) { 7742 PetscScalar fval = flip[i]; 7743 7744 for (k = 0; k < Ni; ++k) { 7745 valCopy[Ni * (foffset + i) + k] *= fval; 7746 valCopy[Ni * k + (foffset + i)] *= fval; 7747 } 7748 } 7749 } 7750 foffset += fdof; 7751 } 7752 } 7753 } 7754 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7755 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7756 if (NclC) { 7757 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7758 for (f = 0; f < PetscMax(1, Nf); ++f) { 7759 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7760 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7761 } 7762 for (f = 0; f < PetscMax(1, Nf); ++f) { 7763 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7764 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7765 } 7766 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7767 Ncl = NclC; 7768 Ni = NiC; 7769 points = pointsC; 7770 if (values) *values = valuesC; 7771 } 7772 /* 5) Calculate indices */ 7773 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7774 if (Nf) { 7775 PetscInt idxOff; 7776 PetscBool useFieldOffsets; 7777 7778 if (outOffsets) { 7779 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7780 } 7781 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7782 if (useFieldOffsets) { 7783 for (p = 0; p < Ncl; ++p) { 7784 const PetscInt pnt = points[p * 2]; 7785 7786 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7787 } 7788 } else { 7789 for (p = 0; p < Ncl; ++p) { 7790 const PetscInt pnt = points[p * 2]; 7791 7792 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7793 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7794 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7795 * global section. */ 7796 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7797 } 7798 } 7799 } else { 7800 PetscInt off = 0, idxOff; 7801 7802 for (p = 0; p < Ncl; ++p) { 7803 const PetscInt pnt = points[p * 2]; 7804 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7805 7806 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7807 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7808 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7809 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7810 } 7811 } 7812 /* 6) Cleanup */ 7813 for (f = 0; f < PetscMax(1, Nf); ++f) { 7814 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7815 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7816 } 7817 if (NclC) { 7818 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7819 } else { 7820 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7821 } 7822 7823 if (numIndices) *numIndices = Ni; 7824 if (indices) *indices = idx; 7825 PetscFunctionReturn(PETSC_SUCCESS); 7826 } 7827 7828 /*@C 7829 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7830 7831 Not collective 7832 7833 Input Parameters: 7834 + dm - The `DM` 7835 . section - The `PetscSection` describing the points (a local section) 7836 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7837 . point - The point defining the closure 7838 - useClPerm - Use the closure point permutation if available 7839 7840 Output Parameters: 7841 + numIndices - The number of dof indices in the closure of point with the input sections 7842 . indices - The dof indices 7843 . outOffsets - Array to write the field offsets into, or `NULL` 7844 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7845 7846 Level: advanced 7847 7848 Notes: 7849 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7850 7851 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7852 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7853 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7854 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7855 indices (with the above semantics) are implied. 7856 7857 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7858 @*/ 7859 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7860 { 7861 PetscFunctionBegin; 7862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7863 PetscAssertPointer(indices, 7); 7864 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7865 PetscFunctionReturn(PETSC_SUCCESS); 7866 } 7867 7868 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7869 { 7870 DM_Plex *mesh = (DM_Plex *)dm->data; 7871 PetscInt *indices; 7872 PetscInt numIndices; 7873 const PetscScalar *valuesOrig = values; 7874 PetscErrorCode ierr; 7875 7876 PetscFunctionBegin; 7877 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7878 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7879 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7880 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7881 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7882 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 7883 7884 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7885 7886 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7887 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7888 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7889 if (ierr) { 7890 PetscMPIInt rank; 7891 7892 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7893 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7894 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7895 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7896 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7897 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7898 } 7899 if (mesh->printFEM > 1) { 7900 PetscInt i; 7901 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7902 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7903 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7904 } 7905 7906 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7907 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7908 PetscFunctionReturn(PETSC_SUCCESS); 7909 } 7910 7911 /*@C 7912 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7913 7914 Not collective 7915 7916 Input Parameters: 7917 + dm - The `DM` 7918 . section - The section describing the layout in `v`, or `NULL` to use the default section 7919 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 7920 . A - The matrix 7921 . point - The point in the `DM` 7922 . values - The array of values 7923 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7924 7925 Level: intermediate 7926 7927 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7928 @*/ 7929 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7930 { 7931 PetscFunctionBegin; 7932 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 7933 PetscFunctionReturn(PETSC_SUCCESS); 7934 } 7935 7936 /*@C 7937 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 7938 7939 Not collective 7940 7941 Input Parameters: 7942 + dmRow - The `DM` for the row fields 7943 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 7944 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 7945 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 7946 . dmCol - The `DM` for the column fields 7947 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 7948 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 7949 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 7950 . A - The matrix 7951 . point - The point in the `DM` 7952 . values - The array of values 7953 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7954 7955 Level: intermediate 7956 7957 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7958 @*/ 7959 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) 7960 { 7961 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7962 PetscInt *indicesRow, *indicesCol; 7963 PetscInt numIndicesRow, numIndicesCol; 7964 const PetscScalar *valuesOrig = values; 7965 PetscErrorCode ierr; 7966 7967 PetscFunctionBegin; 7968 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7969 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7970 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7971 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7972 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7973 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 7974 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7975 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 7976 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7977 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 7978 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 7979 7980 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7981 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7982 7983 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7984 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7985 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7986 if (ierr) { 7987 PetscMPIInt rank; 7988 7989 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7990 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7991 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7992 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7993 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7994 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7995 } 7996 7997 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7998 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7999 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8000 PetscFunctionReturn(PETSC_SUCCESS); 8001 } 8002 8003 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8004 { 8005 DM_Plex *mesh = (DM_Plex *)dmf->data; 8006 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8007 PetscInt *cpoints = NULL; 8008 PetscInt *findices, *cindices; 8009 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8010 PetscInt foffsets[32], coffsets[32]; 8011 DMPolytopeType ct; 8012 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8013 PetscErrorCode ierr; 8014 8015 PetscFunctionBegin; 8016 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8017 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8018 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8019 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8020 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8021 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8022 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8023 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8024 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8025 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8026 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8027 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8028 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8029 PetscCall(PetscArrayzero(foffsets, 32)); 8030 PetscCall(PetscArrayzero(coffsets, 32)); 8031 /* Column indices */ 8032 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8033 maxFPoints = numCPoints; 8034 /* Compress out points not in the section */ 8035 /* TODO: Squeeze out points with 0 dof as well */ 8036 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8037 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8038 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8039 cpoints[q * 2] = cpoints[p]; 8040 cpoints[q * 2 + 1] = cpoints[p + 1]; 8041 ++q; 8042 } 8043 } 8044 numCPoints = q; 8045 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8046 PetscInt fdof; 8047 8048 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8049 if (!dof) continue; 8050 for (f = 0; f < numFields; ++f) { 8051 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8052 coffsets[f + 1] += fdof; 8053 } 8054 numCIndices += dof; 8055 } 8056 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8057 /* Row indices */ 8058 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8059 { 8060 DMPlexTransform tr; 8061 DMPolytopeType *rct; 8062 PetscInt *rsize, *rcone, *rornt, Nt; 8063 8064 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8065 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8066 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8067 numSubcells = rsize[Nt - 1]; 8068 PetscCall(DMPlexTransformDestroy(&tr)); 8069 } 8070 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8071 for (r = 0, q = 0; r < numSubcells; ++r) { 8072 /* TODO Map from coarse to fine cells */ 8073 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8074 /* Compress out points not in the section */ 8075 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8076 for (p = 0; p < numFPoints * 2; p += 2) { 8077 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8078 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8079 if (!dof) continue; 8080 for (s = 0; s < q; ++s) 8081 if (fpoints[p] == ftotpoints[s * 2]) break; 8082 if (s < q) continue; 8083 ftotpoints[q * 2] = fpoints[p]; 8084 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8085 ++q; 8086 } 8087 } 8088 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8089 } 8090 numFPoints = q; 8091 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8092 PetscInt fdof; 8093 8094 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8095 if (!dof) continue; 8096 for (f = 0; f < numFields; ++f) { 8097 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8098 foffsets[f + 1] += fdof; 8099 } 8100 numFIndices += dof; 8101 } 8102 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8103 8104 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8105 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8106 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8107 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8108 if (numFields) { 8109 const PetscInt **permsF[32] = {NULL}; 8110 const PetscInt **permsC[32] = {NULL}; 8111 8112 for (f = 0; f < numFields; f++) { 8113 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8114 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8115 } 8116 for (p = 0; p < numFPoints; p++) { 8117 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8118 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8119 } 8120 for (p = 0; p < numCPoints; p++) { 8121 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8122 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8123 } 8124 for (f = 0; f < numFields; f++) { 8125 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8126 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8127 } 8128 } else { 8129 const PetscInt **permsF = NULL; 8130 const PetscInt **permsC = NULL; 8131 8132 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8133 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8134 for (p = 0, off = 0; p < numFPoints; p++) { 8135 const PetscInt *perm = permsF ? permsF[p] : NULL; 8136 8137 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8138 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8139 } 8140 for (p = 0, off = 0; p < numCPoints; p++) { 8141 const PetscInt *perm = permsC ? permsC[p] : NULL; 8142 8143 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8144 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8145 } 8146 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8147 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8148 } 8149 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8150 /* TODO: flips */ 8151 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8152 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8153 if (ierr) { 8154 PetscMPIInt rank; 8155 8156 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8157 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8158 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8159 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8160 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8161 } 8162 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8163 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8164 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8165 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8166 PetscFunctionReturn(PETSC_SUCCESS); 8167 } 8168 8169 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8170 { 8171 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8172 PetscInt *cpoints = NULL; 8173 PetscInt foffsets[32], coffsets[32]; 8174 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8175 DMPolytopeType ct; 8176 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8177 8178 PetscFunctionBegin; 8179 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8180 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8181 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8182 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8183 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8184 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8185 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8186 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8187 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8188 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8189 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8190 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8191 PetscCall(PetscArrayzero(foffsets, 32)); 8192 PetscCall(PetscArrayzero(coffsets, 32)); 8193 /* Column indices */ 8194 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8195 maxFPoints = numCPoints; 8196 /* Compress out points not in the section */ 8197 /* TODO: Squeeze out points with 0 dof as well */ 8198 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8199 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8200 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8201 cpoints[q * 2] = cpoints[p]; 8202 cpoints[q * 2 + 1] = cpoints[p + 1]; 8203 ++q; 8204 } 8205 } 8206 numCPoints = q; 8207 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8208 PetscInt fdof; 8209 8210 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8211 if (!dof) continue; 8212 for (f = 0; f < numFields; ++f) { 8213 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8214 coffsets[f + 1] += fdof; 8215 } 8216 numCIndices += dof; 8217 } 8218 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8219 /* Row indices */ 8220 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8221 { 8222 DMPlexTransform tr; 8223 DMPolytopeType *rct; 8224 PetscInt *rsize, *rcone, *rornt, Nt; 8225 8226 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8227 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8228 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8229 numSubcells = rsize[Nt - 1]; 8230 PetscCall(DMPlexTransformDestroy(&tr)); 8231 } 8232 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8233 for (r = 0, q = 0; r < numSubcells; ++r) { 8234 /* TODO Map from coarse to fine cells */ 8235 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8236 /* Compress out points not in the section */ 8237 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8238 for (p = 0; p < numFPoints * 2; p += 2) { 8239 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8240 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8241 if (!dof) continue; 8242 for (s = 0; s < q; ++s) 8243 if (fpoints[p] == ftotpoints[s * 2]) break; 8244 if (s < q) continue; 8245 ftotpoints[q * 2] = fpoints[p]; 8246 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8247 ++q; 8248 } 8249 } 8250 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8251 } 8252 numFPoints = q; 8253 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8254 PetscInt fdof; 8255 8256 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8257 if (!dof) continue; 8258 for (f = 0; f < numFields; ++f) { 8259 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8260 foffsets[f + 1] += fdof; 8261 } 8262 numFIndices += dof; 8263 } 8264 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8265 8266 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8267 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8268 if (numFields) { 8269 const PetscInt **permsF[32] = {NULL}; 8270 const PetscInt **permsC[32] = {NULL}; 8271 8272 for (f = 0; f < numFields; f++) { 8273 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8274 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8275 } 8276 for (p = 0; p < numFPoints; p++) { 8277 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8278 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8279 } 8280 for (p = 0; p < numCPoints; p++) { 8281 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8282 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8283 } 8284 for (f = 0; f < numFields; f++) { 8285 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8286 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8287 } 8288 } else { 8289 const PetscInt **permsF = NULL; 8290 const PetscInt **permsC = NULL; 8291 8292 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8293 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8294 for (p = 0, off = 0; p < numFPoints; p++) { 8295 const PetscInt *perm = permsF ? permsF[p] : NULL; 8296 8297 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8298 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8299 } 8300 for (p = 0, off = 0; p < numCPoints; p++) { 8301 const PetscInt *perm = permsC ? permsC[p] : NULL; 8302 8303 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8304 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8305 } 8306 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8307 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8308 } 8309 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8310 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8311 PetscFunctionReturn(PETSC_SUCCESS); 8312 } 8313 8314 /*@C 8315 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8316 8317 Input Parameter: 8318 . dm - The `DMPLEX` object 8319 8320 Output Parameter: 8321 . cellHeight - The height of a cell 8322 8323 Level: developer 8324 8325 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8326 @*/ 8327 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8328 { 8329 DM_Plex *mesh = (DM_Plex *)dm->data; 8330 8331 PetscFunctionBegin; 8332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8333 PetscAssertPointer(cellHeight, 2); 8334 *cellHeight = mesh->vtkCellHeight; 8335 PetscFunctionReturn(PETSC_SUCCESS); 8336 } 8337 8338 /*@C 8339 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8340 8341 Input Parameters: 8342 + dm - The `DMPLEX` object 8343 - cellHeight - The height of a cell 8344 8345 Level: developer 8346 8347 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8348 @*/ 8349 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8350 { 8351 DM_Plex *mesh = (DM_Plex *)dm->data; 8352 8353 PetscFunctionBegin; 8354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8355 mesh->vtkCellHeight = cellHeight; 8356 PetscFunctionReturn(PETSC_SUCCESS); 8357 } 8358 8359 /*@ 8360 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8361 8362 Input Parameters: 8363 + dm - The `DMPLEX` object 8364 - ct - The `DMPolytopeType` of the cell 8365 8366 Output Parameters: 8367 + start - The first cell of this type, or `NULL` 8368 - end - The upper bound on this celltype, or `NULL` 8369 8370 Level: advanced 8371 8372 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8373 @*/ 8374 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8375 { 8376 DM_Plex *mesh = (DM_Plex *)dm->data; 8377 DMLabel label; 8378 PetscInt pStart, pEnd; 8379 8380 PetscFunctionBegin; 8381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8382 if (start) { 8383 PetscAssertPointer(start, 3); 8384 *start = 0; 8385 } 8386 if (end) { 8387 PetscAssertPointer(end, 4); 8388 *end = 0; 8389 } 8390 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8391 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8392 if (mesh->tr) { 8393 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8394 } else { 8395 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8396 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8397 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8398 } 8399 PetscFunctionReturn(PETSC_SUCCESS); 8400 } 8401 8402 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8403 { 8404 PetscSection section, globalSection; 8405 PetscInt *numbers, p; 8406 8407 PetscFunctionBegin; 8408 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8409 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8410 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8411 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8412 PetscCall(PetscSectionSetUp(section)); 8413 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8414 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8415 for (p = pStart; p < pEnd; ++p) { 8416 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8417 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8418 else numbers[p - pStart] += shift; 8419 } 8420 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8421 if (globalSize) { 8422 PetscLayout layout; 8423 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8424 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8425 PetscCall(PetscLayoutDestroy(&layout)); 8426 } 8427 PetscCall(PetscSectionDestroy(§ion)); 8428 PetscCall(PetscSectionDestroy(&globalSection)); 8429 PetscFunctionReturn(PETSC_SUCCESS); 8430 } 8431 8432 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8433 { 8434 PetscInt cellHeight, cStart, cEnd; 8435 8436 PetscFunctionBegin; 8437 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8438 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8439 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8440 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8441 PetscFunctionReturn(PETSC_SUCCESS); 8442 } 8443 8444 /*@ 8445 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8446 8447 Input Parameter: 8448 . dm - The `DMPLEX` object 8449 8450 Output Parameter: 8451 . globalCellNumbers - Global cell numbers for all cells on this process 8452 8453 Level: developer 8454 8455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8456 @*/ 8457 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8458 { 8459 DM_Plex *mesh = (DM_Plex *)dm->data; 8460 8461 PetscFunctionBegin; 8462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8463 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8464 *globalCellNumbers = mesh->globalCellNumbers; 8465 PetscFunctionReturn(PETSC_SUCCESS); 8466 } 8467 8468 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8469 { 8470 PetscInt vStart, vEnd; 8471 8472 PetscFunctionBegin; 8473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8474 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8475 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8476 PetscFunctionReturn(PETSC_SUCCESS); 8477 } 8478 8479 /*@ 8480 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8481 8482 Input Parameter: 8483 . dm - The `DMPLEX` object 8484 8485 Output Parameter: 8486 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8487 8488 Level: developer 8489 8490 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8491 @*/ 8492 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8493 { 8494 DM_Plex *mesh = (DM_Plex *)dm->data; 8495 8496 PetscFunctionBegin; 8497 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8498 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8499 *globalVertexNumbers = mesh->globalVertexNumbers; 8500 PetscFunctionReturn(PETSC_SUCCESS); 8501 } 8502 8503 /*@ 8504 DMPlexCreatePointNumbering - Create a global numbering for all points. 8505 8506 Collective 8507 8508 Input Parameter: 8509 . dm - The `DMPLEX` object 8510 8511 Output Parameter: 8512 . globalPointNumbers - Global numbers for all points on this process 8513 8514 Level: developer 8515 8516 Notes: 8517 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8518 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8519 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8520 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8521 8522 The partitioned mesh is 8523 ``` 8524 (2)--0--(3)--1--(4) (1)--0--(2) 8525 ``` 8526 and its global numbering is 8527 ``` 8528 (3)--0--(4)--1--(5)--2--(6) 8529 ``` 8530 Then the global numbering is provided as 8531 ``` 8532 [0] Number of indices in set 5 8533 [0] 0 0 8534 [0] 1 1 8535 [0] 2 3 8536 [0] 3 4 8537 [0] 4 -6 8538 [1] Number of indices in set 3 8539 [1] 0 2 8540 [1] 1 5 8541 [1] 2 6 8542 ``` 8543 8544 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8545 @*/ 8546 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8547 { 8548 IS nums[4]; 8549 PetscInt depths[4], gdepths[4], starts[4]; 8550 PetscInt depth, d, shift = 0; 8551 PetscBool empty = PETSC_FALSE; 8552 8553 PetscFunctionBegin; 8554 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8555 PetscCall(DMPlexGetDepth(dm, &depth)); 8556 // For unstratified meshes use dim instead of depth 8557 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8558 // If any stratum is empty, we must mark all empty 8559 for (d = 0; d <= depth; ++d) { 8560 PetscInt end; 8561 8562 depths[d] = depth - d; 8563 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8564 if (!(starts[d] - end)) empty = PETSC_TRUE; 8565 } 8566 if (empty) 8567 for (d = 0; d <= depth; ++d) { 8568 depths[d] = -1; 8569 starts[d] = -1; 8570 } 8571 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8572 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8573 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]); 8574 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8575 for (d = 0; d <= depth; ++d) { 8576 PetscInt pStart, pEnd, gsize; 8577 8578 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8579 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8580 shift += gsize; 8581 } 8582 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8583 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8584 PetscFunctionReturn(PETSC_SUCCESS); 8585 } 8586 8587 /*@ 8588 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8589 8590 Input Parameter: 8591 . dm - The `DMPLEX` object 8592 8593 Output Parameter: 8594 . ranks - The rank field 8595 8596 Options Database Key: 8597 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8598 8599 Level: intermediate 8600 8601 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8602 @*/ 8603 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8604 { 8605 DM rdm; 8606 PetscFE fe; 8607 PetscScalar *r; 8608 PetscMPIInt rank; 8609 DMPolytopeType ct; 8610 PetscInt dim, cStart, cEnd, c; 8611 PetscBool simplex; 8612 8613 PetscFunctionBeginUser; 8614 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8615 PetscAssertPointer(ranks, 2); 8616 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8617 PetscCall(DMClone(dm, &rdm)); 8618 PetscCall(DMGetDimension(rdm, &dim)); 8619 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8620 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8621 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8622 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8623 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8624 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8625 PetscCall(PetscFEDestroy(&fe)); 8626 PetscCall(DMCreateDS(rdm)); 8627 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8628 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8629 PetscCall(VecGetArray(*ranks, &r)); 8630 for (c = cStart; c < cEnd; ++c) { 8631 PetscScalar *lr; 8632 8633 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8634 if (lr) *lr = rank; 8635 } 8636 PetscCall(VecRestoreArray(*ranks, &r)); 8637 PetscCall(DMDestroy(&rdm)); 8638 PetscFunctionReturn(PETSC_SUCCESS); 8639 } 8640 8641 /*@ 8642 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8643 8644 Input Parameters: 8645 + dm - The `DMPLEX` 8646 - label - The `DMLabel` 8647 8648 Output Parameter: 8649 . val - The label value field 8650 8651 Options Database Key: 8652 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8653 8654 Level: intermediate 8655 8656 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8657 @*/ 8658 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8659 { 8660 DM rdm; 8661 PetscFE fe; 8662 PetscScalar *v; 8663 PetscInt dim, cStart, cEnd, c; 8664 8665 PetscFunctionBeginUser; 8666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8667 PetscAssertPointer(label, 2); 8668 PetscAssertPointer(val, 3); 8669 PetscCall(DMClone(dm, &rdm)); 8670 PetscCall(DMGetDimension(rdm, &dim)); 8671 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8672 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8673 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8674 PetscCall(PetscFEDestroy(&fe)); 8675 PetscCall(DMCreateDS(rdm)); 8676 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8677 PetscCall(DMCreateGlobalVector(rdm, val)); 8678 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8679 PetscCall(VecGetArray(*val, &v)); 8680 for (c = cStart; c < cEnd; ++c) { 8681 PetscScalar *lv; 8682 PetscInt cval; 8683 8684 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8685 PetscCall(DMLabelGetValue(label, c, &cval)); 8686 *lv = cval; 8687 } 8688 PetscCall(VecRestoreArray(*val, &v)); 8689 PetscCall(DMDestroy(&rdm)); 8690 PetscFunctionReturn(PETSC_SUCCESS); 8691 } 8692 8693 /*@ 8694 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8695 8696 Input Parameter: 8697 . dm - The `DMPLEX` object 8698 8699 Level: developer 8700 8701 Notes: 8702 This is a useful diagnostic when creating meshes programmatically. 8703 8704 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8705 8706 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8707 @*/ 8708 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8709 { 8710 PetscSection coneSection, supportSection; 8711 const PetscInt *cone, *support; 8712 PetscInt coneSize, c, supportSize, s; 8713 PetscInt pStart, pEnd, p, pp, csize, ssize; 8714 PetscBool storagecheck = PETSC_TRUE; 8715 8716 PetscFunctionBegin; 8717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8718 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8719 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8720 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8721 /* Check that point p is found in the support of its cone points, and vice versa */ 8722 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8723 for (p = pStart; p < pEnd; ++p) { 8724 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8725 PetscCall(DMPlexGetCone(dm, p, &cone)); 8726 for (c = 0; c < coneSize; ++c) { 8727 PetscBool dup = PETSC_FALSE; 8728 PetscInt d; 8729 for (d = c - 1; d >= 0; --d) { 8730 if (cone[c] == cone[d]) { 8731 dup = PETSC_TRUE; 8732 break; 8733 } 8734 } 8735 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8736 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8737 for (s = 0; s < supportSize; ++s) { 8738 if (support[s] == p) break; 8739 } 8740 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8741 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8742 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8743 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8744 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8745 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8746 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8747 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]); 8748 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8749 } 8750 } 8751 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8752 if (p != pp) { 8753 storagecheck = PETSC_FALSE; 8754 continue; 8755 } 8756 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8757 PetscCall(DMPlexGetSupport(dm, p, &support)); 8758 for (s = 0; s < supportSize; ++s) { 8759 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8760 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8761 for (c = 0; c < coneSize; ++c) { 8762 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8763 if (cone[c] != pp) { 8764 c = 0; 8765 break; 8766 } 8767 if (cone[c] == p) break; 8768 } 8769 if (c >= coneSize) { 8770 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8771 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8772 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8773 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8774 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8775 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8776 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8777 } 8778 } 8779 } 8780 if (storagecheck) { 8781 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8782 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8783 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8784 } 8785 PetscFunctionReturn(PETSC_SUCCESS); 8786 } 8787 8788 /* 8789 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. 8790 */ 8791 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8792 { 8793 DMPolytopeType cct; 8794 PetscInt ptpoints[4]; 8795 const PetscInt *cone, *ccone, *ptcone; 8796 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8797 8798 PetscFunctionBegin; 8799 *unsplit = 0; 8800 switch (ct) { 8801 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8802 ptpoints[npt++] = c; 8803 break; 8804 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8805 PetscCall(DMPlexGetCone(dm, c, &cone)); 8806 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8807 for (cp = 0; cp < coneSize; ++cp) { 8808 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8809 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8810 } 8811 break; 8812 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8813 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8814 PetscCall(DMPlexGetCone(dm, c, &cone)); 8815 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8816 for (cp = 0; cp < coneSize; ++cp) { 8817 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8818 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8819 for (ccp = 0; ccp < cconeSize; ++ccp) { 8820 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8821 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8822 PetscInt p; 8823 for (p = 0; p < npt; ++p) 8824 if (ptpoints[p] == ccone[ccp]) break; 8825 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8826 } 8827 } 8828 } 8829 break; 8830 default: 8831 break; 8832 } 8833 for (pt = 0; pt < npt; ++pt) { 8834 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8835 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8836 } 8837 PetscFunctionReturn(PETSC_SUCCESS); 8838 } 8839 8840 /*@ 8841 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8842 8843 Input Parameters: 8844 + dm - The `DMPLEX` object 8845 - cellHeight - Normally 0 8846 8847 Level: developer 8848 8849 Notes: 8850 This is a useful diagnostic when creating meshes programmatically. 8851 Currently applicable only to homogeneous simplex or tensor meshes. 8852 8853 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8854 8855 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8856 @*/ 8857 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8858 { 8859 DMPlexInterpolatedFlag interp; 8860 DMPolytopeType ct; 8861 PetscInt vStart, vEnd, cStart, cEnd, c; 8862 8863 PetscFunctionBegin; 8864 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8865 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8866 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8867 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8868 for (c = cStart; c < cEnd; ++c) { 8869 PetscInt *closure = NULL; 8870 PetscInt coneSize, closureSize, cl, Nv = 0; 8871 8872 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8873 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8874 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8875 if (interp == DMPLEX_INTERPOLATED_FULL) { 8876 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8877 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)); 8878 } 8879 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8880 for (cl = 0; cl < closureSize * 2; cl += 2) { 8881 const PetscInt p = closure[cl]; 8882 if ((p >= vStart) && (p < vEnd)) ++Nv; 8883 } 8884 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8885 /* Special Case: Tensor faces with identified vertices */ 8886 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8887 PetscInt unsplit; 8888 8889 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8890 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8891 } 8892 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)); 8893 } 8894 PetscFunctionReturn(PETSC_SUCCESS); 8895 } 8896 8897 /*@ 8898 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8899 8900 Collective 8901 8902 Input Parameters: 8903 + dm - The `DMPLEX` object 8904 - cellHeight - Normally 0 8905 8906 Level: developer 8907 8908 Notes: 8909 This is a useful diagnostic when creating meshes programmatically. 8910 This routine is only relevant for meshes that are fully interpolated across all ranks. 8911 It will error out if a partially interpolated mesh is given on some rank. 8912 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8913 8914 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8915 8916 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8917 @*/ 8918 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8919 { 8920 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8921 DMPlexInterpolatedFlag interpEnum; 8922 8923 PetscFunctionBegin; 8924 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8925 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8926 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 8927 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8928 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 8929 PetscFunctionReturn(PETSC_SUCCESS); 8930 } 8931 8932 PetscCall(DMGetDimension(dm, &dim)); 8933 PetscCall(DMPlexGetDepth(dm, &depth)); 8934 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8935 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8936 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8937 for (c = cStart; c < cEnd; ++c) { 8938 const PetscInt *cone, *ornt, *faceSizes, *faces; 8939 const DMPolytopeType *faceTypes; 8940 DMPolytopeType ct; 8941 PetscInt numFaces, coneSize, f; 8942 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8943 8944 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8945 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8946 if (unsplit) continue; 8947 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8948 PetscCall(DMPlexGetCone(dm, c, &cone)); 8949 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8950 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8951 for (cl = 0; cl < closureSize * 2; cl += 2) { 8952 const PetscInt p = closure[cl]; 8953 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8954 } 8955 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8956 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); 8957 for (f = 0; f < numFaces; ++f) { 8958 DMPolytopeType fct; 8959 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8960 8961 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8962 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8963 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8964 const PetscInt p = fclosure[cl]; 8965 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8966 } 8967 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]); 8968 for (v = 0; v < fnumCorners; ++v) { 8969 if (fclosure[v] != faces[fOff + v]) { 8970 PetscInt v1; 8971 8972 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8973 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8974 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8975 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8976 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8977 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]); 8978 } 8979 } 8980 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8981 fOff += faceSizes[f]; 8982 } 8983 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8984 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8985 } 8986 } 8987 PetscFunctionReturn(PETSC_SUCCESS); 8988 } 8989 8990 /*@ 8991 DMPlexCheckGeometry - Check the geometry of mesh cells 8992 8993 Input Parameter: 8994 . dm - The `DMPLEX` object 8995 8996 Level: developer 8997 8998 Notes: 8999 This is a useful diagnostic when creating meshes programmatically. 9000 9001 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9002 9003 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9004 @*/ 9005 PetscErrorCode DMPlexCheckGeometry(DM dm) 9006 { 9007 Vec coordinates; 9008 PetscReal detJ, J[9], refVol = 1.0; 9009 PetscReal vol; 9010 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9011 9012 PetscFunctionBegin; 9013 PetscCall(DMGetDimension(dm, &dim)); 9014 PetscCall(DMGetCoordinateDim(dm, &dE)); 9015 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9016 PetscCall(DMPlexGetDepth(dm, &depth)); 9017 for (d = 0; d < dim; ++d) refVol *= 2.0; 9018 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9019 /* Make sure local coordinates are created, because that step is collective */ 9020 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9021 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9022 for (c = cStart; c < cEnd; ++c) { 9023 DMPolytopeType ct; 9024 PetscInt unsplit; 9025 PetscBool ignoreZeroVol = PETSC_FALSE; 9026 9027 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9028 switch (ct) { 9029 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9030 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9031 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9032 ignoreZeroVol = PETSC_TRUE; 9033 break; 9034 default: 9035 break; 9036 } 9037 switch (ct) { 9038 case DM_POLYTOPE_TRI_PRISM: 9039 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9040 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9041 case DM_POLYTOPE_PYRAMID: 9042 continue; 9043 default: 9044 break; 9045 } 9046 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9047 if (unsplit) continue; 9048 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9049 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); 9050 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9051 /* This should work with periodicity since DG coordinates should be used */ 9052 if (depth > 1) { 9053 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9054 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); 9055 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9056 } 9057 } 9058 PetscFunctionReturn(PETSC_SUCCESS); 9059 } 9060 9061 /*@ 9062 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9063 9064 Collective 9065 9066 Input Parameters: 9067 + dm - The `DMPLEX` object 9068 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9069 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9070 9071 Level: developer 9072 9073 Notes: 9074 This is mainly intended for debugging/testing purposes. 9075 9076 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9077 9078 Extra roots can come from periodic cuts, where additional points appear on the boundary 9079 9080 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9081 @*/ 9082 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9083 { 9084 PetscInt l, nleaves, nroots, overlap; 9085 const PetscInt *locals; 9086 const PetscSFNode *remotes; 9087 PetscBool distributed; 9088 MPI_Comm comm; 9089 PetscMPIInt rank; 9090 9091 PetscFunctionBegin; 9092 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9093 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9094 else pointSF = dm->sf; 9095 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9096 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9097 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9098 { 9099 PetscMPIInt mpiFlag; 9100 9101 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9102 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9103 } 9104 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9105 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9106 if (!distributed) { 9107 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); 9108 PetscFunctionReturn(PETSC_SUCCESS); 9109 } 9110 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); 9111 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9112 9113 /* Check SF graph is compatible with DMPlex chart */ 9114 { 9115 PetscInt pStart, pEnd, maxLeaf; 9116 9117 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9118 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9119 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9120 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9121 } 9122 9123 /* Check Point SF has no local points referenced */ 9124 for (l = 0; l < nleaves; l++) { 9125 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); 9126 } 9127 9128 /* Check there are no cells in interface */ 9129 if (!overlap) { 9130 PetscInt cellHeight, cStart, cEnd; 9131 9132 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9133 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9134 for (l = 0; l < nleaves; ++l) { 9135 const PetscInt point = locals ? locals[l] : l; 9136 9137 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9138 } 9139 } 9140 9141 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9142 { 9143 const PetscInt *rootdegree; 9144 9145 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9146 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9147 for (l = 0; l < nleaves; ++l) { 9148 const PetscInt point = locals ? locals[l] : l; 9149 const PetscInt *cone; 9150 PetscInt coneSize, c, idx; 9151 9152 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9153 PetscCall(DMPlexGetCone(dm, point, &cone)); 9154 for (c = 0; c < coneSize; ++c) { 9155 if (!rootdegree[cone[c]]) { 9156 if (locals) { 9157 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9158 } else { 9159 idx = (cone[c] < nleaves) ? cone[c] : -1; 9160 } 9161 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9162 } 9163 } 9164 } 9165 } 9166 PetscFunctionReturn(PETSC_SUCCESS); 9167 } 9168 9169 /*@ 9170 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9171 9172 Input Parameter: 9173 . dm - The `DMPLEX` object 9174 9175 Level: developer 9176 9177 Notes: 9178 This is a useful diagnostic when creating meshes programmatically. 9179 9180 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9181 9182 Currently does not include `DMPlexCheckCellShape()`. 9183 9184 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9185 @*/ 9186 PetscErrorCode DMPlexCheck(DM dm) 9187 { 9188 PetscInt cellHeight; 9189 9190 PetscFunctionBegin; 9191 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9192 PetscCall(DMPlexCheckSymmetry(dm)); 9193 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9194 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9195 PetscCall(DMPlexCheckGeometry(dm)); 9196 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9197 PetscCall(DMPlexCheckInterfaceCones(dm)); 9198 PetscFunctionReturn(PETSC_SUCCESS); 9199 } 9200 9201 typedef struct cell_stats { 9202 PetscReal min, max, sum, squaresum; 9203 PetscInt count; 9204 } cell_stats_t; 9205 9206 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9207 { 9208 PetscInt i, N = *len; 9209 9210 for (i = 0; i < N; i++) { 9211 cell_stats_t *A = (cell_stats_t *)a; 9212 cell_stats_t *B = (cell_stats_t *)b; 9213 9214 B->min = PetscMin(A->min, B->min); 9215 B->max = PetscMax(A->max, B->max); 9216 B->sum += A->sum; 9217 B->squaresum += A->squaresum; 9218 B->count += A->count; 9219 } 9220 } 9221 9222 /*@ 9223 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9224 9225 Collective 9226 9227 Input Parameters: 9228 + dm - The `DMPLEX` object 9229 . output - If true, statistics will be displayed on `stdout` 9230 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9231 9232 Level: developer 9233 9234 Notes: 9235 This is mainly intended for debugging/testing purposes. 9236 9237 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9238 9239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9240 @*/ 9241 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9242 { 9243 DM dmCoarse; 9244 cell_stats_t stats, globalStats; 9245 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9246 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9247 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9248 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9249 PetscMPIInt rank, size; 9250 9251 PetscFunctionBegin; 9252 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9253 stats.min = PETSC_MAX_REAL; 9254 stats.max = PETSC_MIN_REAL; 9255 stats.sum = stats.squaresum = 0.; 9256 stats.count = 0; 9257 9258 PetscCallMPI(MPI_Comm_size(comm, &size)); 9259 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9260 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9261 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9262 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9263 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9264 for (c = cStart; c < cEnd; c++) { 9265 PetscInt i; 9266 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9267 9268 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9269 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9270 for (i = 0; i < PetscSqr(cdim); ++i) { 9271 frobJ += J[i] * J[i]; 9272 frobInvJ += invJ[i] * invJ[i]; 9273 } 9274 cond2 = frobJ * frobInvJ; 9275 cond = PetscSqrtReal(cond2); 9276 9277 stats.min = PetscMin(stats.min, cond); 9278 stats.max = PetscMax(stats.max, cond); 9279 stats.sum += cond; 9280 stats.squaresum += cond2; 9281 stats.count++; 9282 if (output && cond > limit) { 9283 PetscSection coordSection; 9284 Vec coordsLocal; 9285 PetscScalar *coords = NULL; 9286 PetscInt Nv, d, clSize, cl, *closure = NULL; 9287 9288 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9289 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9290 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9291 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9292 for (i = 0; i < Nv / cdim; ++i) { 9293 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9294 for (d = 0; d < cdim; ++d) { 9295 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9296 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9297 } 9298 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9299 } 9300 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9301 for (cl = 0; cl < clSize * 2; cl += 2) { 9302 const PetscInt edge = closure[cl]; 9303 9304 if ((edge >= eStart) && (edge < eEnd)) { 9305 PetscReal len; 9306 9307 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9308 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9309 } 9310 } 9311 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9312 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9313 } 9314 } 9315 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9316 9317 if (size > 1) { 9318 PetscMPIInt blockLengths[2] = {4, 1}; 9319 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9320 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9321 MPI_Op statReduce; 9322 9323 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9324 PetscCallMPI(MPI_Type_commit(&statType)); 9325 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9326 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9327 PetscCallMPI(MPI_Op_free(&statReduce)); 9328 PetscCallMPI(MPI_Type_free(&statType)); 9329 } else { 9330 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9331 } 9332 if (rank == 0) { 9333 count = globalStats.count; 9334 min = globalStats.min; 9335 max = globalStats.max; 9336 mean = globalStats.sum / globalStats.count; 9337 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9338 } 9339 9340 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)); 9341 PetscCall(PetscFree2(J, invJ)); 9342 9343 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9344 if (dmCoarse) { 9345 PetscBool isplex; 9346 9347 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9348 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9349 } 9350 PetscFunctionReturn(PETSC_SUCCESS); 9351 } 9352 9353 /*@ 9354 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9355 orthogonal quality below given tolerance. 9356 9357 Collective 9358 9359 Input Parameters: 9360 + dm - The `DMPLEX` object 9361 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9362 - atol - [0, 1] Absolute tolerance for tagging cells. 9363 9364 Output Parameters: 9365 + OrthQual - `Vec` containing orthogonal quality per cell 9366 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9367 9368 Options Database Keys: 9369 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9370 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9371 9372 Level: intermediate 9373 9374 Notes: 9375 Orthogonal quality is given by the following formula\: 9376 9377 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9378 9379 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 9380 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9381 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9382 calculating the cosine of the angle between these vectors. 9383 9384 Orthogonal quality ranges from 1 (best) to 0 (worst). 9385 9386 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9387 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9388 9389 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9390 9391 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9392 @*/ 9393 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9394 { 9395 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9396 PetscInt *idx; 9397 PetscScalar *oqVals; 9398 const PetscScalar *cellGeomArr, *faceGeomArr; 9399 PetscReal *ci, *fi, *Ai; 9400 MPI_Comm comm; 9401 Vec cellgeom, facegeom; 9402 DM dmFace, dmCell; 9403 IS glob; 9404 ISLocalToGlobalMapping ltog; 9405 PetscViewer vwr; 9406 9407 PetscFunctionBegin; 9408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9409 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9410 PetscAssertPointer(OrthQual, 4); 9411 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9412 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9413 PetscCall(DMGetDimension(dm, &nc)); 9414 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9415 { 9416 DMPlexInterpolatedFlag interpFlag; 9417 9418 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9419 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9420 PetscMPIInt rank; 9421 9422 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9423 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9424 } 9425 } 9426 if (OrthQualLabel) { 9427 PetscAssertPointer(OrthQualLabel, 5); 9428 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9429 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9430 } else { 9431 *OrthQualLabel = NULL; 9432 } 9433 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9434 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9435 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9436 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9437 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9438 PetscCall(VecCreate(comm, OrthQual)); 9439 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9440 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9441 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9442 PetscCall(VecSetUp(*OrthQual)); 9443 PetscCall(ISDestroy(&glob)); 9444 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9445 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9446 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9447 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9448 PetscCall(VecGetDM(cellgeom, &dmCell)); 9449 PetscCall(VecGetDM(facegeom, &dmFace)); 9450 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9451 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9452 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9453 PetscInt cellarr[2], *adj = NULL; 9454 PetscScalar *cArr, *fArr; 9455 PetscReal minvalc = 1.0, minvalf = 1.0; 9456 PetscFVCellGeom *cg; 9457 9458 idx[cellIter] = cell - cStart; 9459 cellarr[0] = cell; 9460 /* Make indexing into cellGeom easier */ 9461 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9462 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9463 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9464 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9465 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9466 PetscInt i; 9467 const PetscInt neigh = adj[cellneigh]; 9468 PetscReal normci = 0, normfi = 0, normai = 0; 9469 PetscFVCellGeom *cgneigh; 9470 PetscFVFaceGeom *fg; 9471 9472 /* Don't count ourselves in the neighbor list */ 9473 if (neigh == cell) continue; 9474 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9475 cellarr[1] = neigh; 9476 { 9477 PetscInt numcovpts; 9478 const PetscInt *covpts; 9479 9480 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9481 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9482 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9483 } 9484 9485 /* Compute c_i, f_i and their norms */ 9486 for (i = 0; i < nc; i++) { 9487 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9488 fi[i] = fg->centroid[i] - cg->centroid[i]; 9489 Ai[i] = fg->normal[i]; 9490 normci += PetscPowReal(ci[i], 2); 9491 normfi += PetscPowReal(fi[i], 2); 9492 normai += PetscPowReal(Ai[i], 2); 9493 } 9494 normci = PetscSqrtReal(normci); 9495 normfi = PetscSqrtReal(normfi); 9496 normai = PetscSqrtReal(normai); 9497 9498 /* Normalize and compute for each face-cell-normal pair */ 9499 for (i = 0; i < nc; i++) { 9500 ci[i] = ci[i] / normci; 9501 fi[i] = fi[i] / normfi; 9502 Ai[i] = Ai[i] / normai; 9503 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9504 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9505 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9506 } 9507 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9508 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9509 } 9510 PetscCall(PetscFree(adj)); 9511 PetscCall(PetscFree2(cArr, fArr)); 9512 /* Defer to cell if they're equal */ 9513 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9514 if (OrthQualLabel) { 9515 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9516 } 9517 } 9518 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9519 PetscCall(VecAssemblyBegin(*OrthQual)); 9520 PetscCall(VecAssemblyEnd(*OrthQual)); 9521 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9522 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9523 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9524 if (OrthQualLabel) { 9525 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9526 } 9527 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9528 PetscCall(PetscViewerDestroy(&vwr)); 9529 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9530 PetscFunctionReturn(PETSC_SUCCESS); 9531 } 9532 9533 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9534 * interpolator construction */ 9535 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9536 { 9537 PetscSection section, newSection, gsection; 9538 PetscSF sf; 9539 PetscBool hasConstraints, ghasConstraints; 9540 9541 PetscFunctionBegin; 9542 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9543 PetscAssertPointer(odm, 2); 9544 PetscCall(DMGetLocalSection(dm, §ion)); 9545 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9546 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9547 if (!ghasConstraints) { 9548 PetscCall(PetscObjectReference((PetscObject)dm)); 9549 *odm = dm; 9550 PetscFunctionReturn(PETSC_SUCCESS); 9551 } 9552 PetscCall(DMClone(dm, odm)); 9553 PetscCall(DMCopyFields(dm, *odm)); 9554 PetscCall(DMGetLocalSection(*odm, &newSection)); 9555 PetscCall(DMGetPointSF(*odm, &sf)); 9556 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9557 PetscCall(DMSetGlobalSection(*odm, gsection)); 9558 PetscCall(PetscSectionDestroy(&gsection)); 9559 PetscFunctionReturn(PETSC_SUCCESS); 9560 } 9561 9562 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9563 { 9564 DM dmco, dmfo; 9565 Mat interpo; 9566 Vec rscale; 9567 Vec cglobalo, clocal; 9568 Vec fglobal, fglobalo, flocal; 9569 PetscBool regular; 9570 9571 PetscFunctionBegin; 9572 PetscCall(DMGetFullDM(dmc, &dmco)); 9573 PetscCall(DMGetFullDM(dmf, &dmfo)); 9574 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9575 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9576 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9577 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9578 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9579 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9580 PetscCall(VecSet(cglobalo, 0.)); 9581 PetscCall(VecSet(clocal, 0.)); 9582 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9583 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9584 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9585 PetscCall(VecSet(fglobal, 0.)); 9586 PetscCall(VecSet(fglobalo, 0.)); 9587 PetscCall(VecSet(flocal, 0.)); 9588 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9589 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9590 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9591 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9592 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9593 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9594 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9595 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9596 *shift = fglobal; 9597 PetscCall(VecDestroy(&flocal)); 9598 PetscCall(VecDestroy(&fglobalo)); 9599 PetscCall(VecDestroy(&clocal)); 9600 PetscCall(VecDestroy(&cglobalo)); 9601 PetscCall(VecDestroy(&rscale)); 9602 PetscCall(MatDestroy(&interpo)); 9603 PetscCall(DMDestroy(&dmfo)); 9604 PetscCall(DMDestroy(&dmco)); 9605 PetscFunctionReturn(PETSC_SUCCESS); 9606 } 9607 9608 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9609 { 9610 PetscObject shifto; 9611 Vec shift; 9612 9613 PetscFunctionBegin; 9614 if (!interp) { 9615 Vec rscale; 9616 9617 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9618 PetscCall(VecDestroy(&rscale)); 9619 } else { 9620 PetscCall(PetscObjectReference((PetscObject)interp)); 9621 } 9622 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9623 if (!shifto) { 9624 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9625 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9626 shifto = (PetscObject)shift; 9627 PetscCall(VecDestroy(&shift)); 9628 } 9629 shift = (Vec)shifto; 9630 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9631 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9632 PetscCall(MatDestroy(&interp)); 9633 PetscFunctionReturn(PETSC_SUCCESS); 9634 } 9635 9636 /* Pointwise interpolation 9637 Just code FEM for now 9638 u^f = I u^c 9639 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9640 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9641 I_{ij} = psi^f_i phi^c_j 9642 */ 9643 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9644 { 9645 PetscSection gsc, gsf; 9646 PetscInt m, n; 9647 void *ctx; 9648 DM cdm; 9649 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9650 9651 PetscFunctionBegin; 9652 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9653 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9654 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9655 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9656 9657 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9658 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9659 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9660 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9661 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9662 9663 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9664 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9665 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9666 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9667 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9668 if (scaling) { 9669 /* Use naive scaling */ 9670 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9671 } 9672 PetscFunctionReturn(PETSC_SUCCESS); 9673 } 9674 9675 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9676 { 9677 VecScatter ctx; 9678 9679 PetscFunctionBegin; 9680 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9681 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9682 PetscCall(VecScatterDestroy(&ctx)); 9683 PetscFunctionReturn(PETSC_SUCCESS); 9684 } 9685 9686 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[]) 9687 { 9688 const PetscInt Nc = uOff[1] - uOff[0]; 9689 PetscInt c; 9690 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9691 } 9692 9693 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9694 { 9695 DM dmc; 9696 PetscDS ds; 9697 Vec ones, locmass; 9698 IS cellIS; 9699 PetscFormKey key; 9700 PetscInt depth; 9701 9702 PetscFunctionBegin; 9703 PetscCall(DMClone(dm, &dmc)); 9704 PetscCall(DMCopyDisc(dm, dmc)); 9705 PetscCall(DMGetDS(dmc, &ds)); 9706 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9707 PetscCall(DMCreateGlobalVector(dmc, mass)); 9708 PetscCall(DMGetLocalVector(dmc, &ones)); 9709 PetscCall(DMGetLocalVector(dmc, &locmass)); 9710 PetscCall(DMPlexGetDepth(dmc, &depth)); 9711 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9712 PetscCall(VecSet(locmass, 0.0)); 9713 PetscCall(VecSet(ones, 1.0)); 9714 key.label = NULL; 9715 key.value = 0; 9716 key.field = 0; 9717 key.part = 0; 9718 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9719 PetscCall(ISDestroy(&cellIS)); 9720 PetscCall(VecSet(*mass, 0.0)); 9721 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9722 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9723 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9724 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9725 PetscCall(DMDestroy(&dmc)); 9726 PetscFunctionReturn(PETSC_SUCCESS); 9727 } 9728 9729 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9730 { 9731 PetscSection gsc, gsf; 9732 PetscInt m, n; 9733 void *ctx; 9734 DM cdm; 9735 PetscBool regular; 9736 9737 PetscFunctionBegin; 9738 if (dmFine == dmCoarse) { 9739 DM dmc; 9740 PetscDS ds; 9741 PetscWeakForm wf; 9742 Vec u; 9743 IS cellIS; 9744 PetscFormKey key; 9745 PetscInt depth; 9746 9747 PetscCall(DMClone(dmFine, &dmc)); 9748 PetscCall(DMCopyDisc(dmFine, dmc)); 9749 PetscCall(DMGetDS(dmc, &ds)); 9750 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9751 PetscCall(PetscWeakFormClear(wf)); 9752 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9753 PetscCall(DMCreateMatrix(dmc, mass)); 9754 PetscCall(DMGetLocalVector(dmc, &u)); 9755 PetscCall(DMPlexGetDepth(dmc, &depth)); 9756 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9757 PetscCall(MatZeroEntries(*mass)); 9758 key.label = NULL; 9759 key.value = 0; 9760 key.field = 0; 9761 key.part = 0; 9762 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9763 PetscCall(ISDestroy(&cellIS)); 9764 PetscCall(DMRestoreLocalVector(dmc, &u)); 9765 PetscCall(DMDestroy(&dmc)); 9766 } else { 9767 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9768 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9769 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9770 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9771 9772 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9773 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9774 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9775 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9776 9777 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9778 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9779 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9780 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9781 } 9782 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9783 PetscFunctionReturn(PETSC_SUCCESS); 9784 } 9785 9786 /*@ 9787 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9788 9789 Input Parameter: 9790 . dm - The `DMPLEX` object 9791 9792 Output Parameter: 9793 . regular - The flag 9794 9795 Level: intermediate 9796 9797 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9798 @*/ 9799 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9800 { 9801 PetscFunctionBegin; 9802 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9803 PetscAssertPointer(regular, 2); 9804 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9805 PetscFunctionReturn(PETSC_SUCCESS); 9806 } 9807 9808 /*@ 9809 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9810 9811 Input Parameters: 9812 + dm - The `DMPLEX` object 9813 - regular - The flag 9814 9815 Level: intermediate 9816 9817 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9818 @*/ 9819 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9820 { 9821 PetscFunctionBegin; 9822 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9823 ((DM_Plex *)dm->data)->regularRefinement = regular; 9824 PetscFunctionReturn(PETSC_SUCCESS); 9825 } 9826 9827 /*@ 9828 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9829 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9830 9831 Not Collective 9832 9833 Input Parameter: 9834 . dm - The `DMPLEX` object 9835 9836 Output Parameters: 9837 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9838 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9839 9840 Level: intermediate 9841 9842 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9843 @*/ 9844 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9845 { 9846 DM_Plex *plex = (DM_Plex *)dm->data; 9847 9848 PetscFunctionBegin; 9849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9850 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9851 if (anchorSection) *anchorSection = plex->anchorSection; 9852 if (anchorIS) *anchorIS = plex->anchorIS; 9853 PetscFunctionReturn(PETSC_SUCCESS); 9854 } 9855 9856 /*@ 9857 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 9858 9859 Collective 9860 9861 Input Parameters: 9862 + dm - The `DMPLEX` object 9863 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9864 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9865 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9866 9867 Level: intermediate 9868 9869 Notes: 9870 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 9871 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 9872 combination of other points' degrees of freedom. 9873 9874 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9875 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9876 9877 The reference counts of `anchorSection` and `anchorIS` are incremented. 9878 9879 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9880 @*/ 9881 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9882 { 9883 DM_Plex *plex = (DM_Plex *)dm->data; 9884 PetscMPIInt result; 9885 9886 PetscFunctionBegin; 9887 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9888 if (anchorSection) { 9889 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9890 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9891 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9892 } 9893 if (anchorIS) { 9894 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9895 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9896 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9897 } 9898 9899 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9900 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9901 plex->anchorSection = anchorSection; 9902 9903 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9904 PetscCall(ISDestroy(&plex->anchorIS)); 9905 plex->anchorIS = anchorIS; 9906 9907 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9908 PetscInt size, a, pStart, pEnd; 9909 const PetscInt *anchors; 9910 9911 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9912 PetscCall(ISGetLocalSize(anchorIS, &size)); 9913 PetscCall(ISGetIndices(anchorIS, &anchors)); 9914 for (a = 0; a < size; a++) { 9915 PetscInt p; 9916 9917 p = anchors[a]; 9918 if (p >= pStart && p < pEnd) { 9919 PetscInt dof; 9920 9921 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9922 if (dof) { 9923 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9924 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9925 } 9926 } 9927 } 9928 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9929 } 9930 /* reset the generic constraints */ 9931 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9932 PetscFunctionReturn(PETSC_SUCCESS); 9933 } 9934 9935 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9936 { 9937 PetscSection anchorSection; 9938 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9939 9940 PetscFunctionBegin; 9941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9942 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9943 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9944 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9945 if (numFields) { 9946 PetscInt f; 9947 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9948 9949 for (f = 0; f < numFields; f++) { 9950 PetscInt numComp; 9951 9952 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9953 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9954 } 9955 } 9956 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9957 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9958 pStart = PetscMax(pStart, sStart); 9959 pEnd = PetscMin(pEnd, sEnd); 9960 pEnd = PetscMax(pStart, pEnd); 9961 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9962 for (p = pStart; p < pEnd; p++) { 9963 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9964 if (dof) { 9965 PetscCall(PetscSectionGetDof(section, p, &dof)); 9966 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9967 for (f = 0; f < numFields; f++) { 9968 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9969 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9970 } 9971 } 9972 } 9973 PetscCall(PetscSectionSetUp(*cSec)); 9974 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9975 PetscFunctionReturn(PETSC_SUCCESS); 9976 } 9977 9978 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9979 { 9980 PetscSection aSec; 9981 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9982 const PetscInt *anchors; 9983 PetscInt numFields, f; 9984 IS aIS; 9985 MatType mtype; 9986 PetscBool iscuda, iskokkos; 9987 9988 PetscFunctionBegin; 9989 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9990 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9991 PetscCall(PetscSectionGetStorageSize(section, &n)); 9992 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9993 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9994 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9995 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9996 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9997 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9998 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9999 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10000 else mtype = MATSEQAIJ; 10001 PetscCall(MatSetType(*cMat, mtype)); 10002 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10003 PetscCall(ISGetIndices(aIS, &anchors)); 10004 /* cSec will be a subset of aSec and section */ 10005 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10006 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10007 PetscCall(PetscMalloc1(m + 1, &i)); 10008 i[0] = 0; 10009 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10010 for (p = pStart; p < pEnd; p++) { 10011 PetscInt rDof, rOff, r; 10012 10013 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10014 if (!rDof) continue; 10015 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10016 if (numFields) { 10017 for (f = 0; f < numFields; f++) { 10018 annz = 0; 10019 for (r = 0; r < rDof; r++) { 10020 a = anchors[rOff + r]; 10021 if (a < sStart || a >= sEnd) continue; 10022 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10023 annz += aDof; 10024 } 10025 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10026 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10027 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10028 } 10029 } else { 10030 annz = 0; 10031 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10032 for (q = 0; q < dof; q++) { 10033 a = anchors[rOff + q]; 10034 if (a < sStart || a >= sEnd) continue; 10035 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10036 annz += aDof; 10037 } 10038 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10039 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10040 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10041 } 10042 } 10043 nnz = i[m]; 10044 PetscCall(PetscMalloc1(nnz, &j)); 10045 offset = 0; 10046 for (p = pStart; p < pEnd; p++) { 10047 if (numFields) { 10048 for (f = 0; f < numFields; f++) { 10049 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10050 for (q = 0; q < dof; q++) { 10051 PetscInt rDof, rOff, r; 10052 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10053 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10054 for (r = 0; r < rDof; r++) { 10055 PetscInt s; 10056 10057 a = anchors[rOff + r]; 10058 if (a < sStart || a >= sEnd) continue; 10059 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10060 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10061 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10062 } 10063 } 10064 } 10065 } else { 10066 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10067 for (q = 0; q < dof; q++) { 10068 PetscInt rDof, rOff, r; 10069 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10070 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10071 for (r = 0; r < rDof; r++) { 10072 PetscInt s; 10073 10074 a = anchors[rOff + r]; 10075 if (a < sStart || a >= sEnd) continue; 10076 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10077 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10078 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10079 } 10080 } 10081 } 10082 } 10083 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10084 PetscCall(PetscFree(i)); 10085 PetscCall(PetscFree(j)); 10086 PetscCall(ISRestoreIndices(aIS, &anchors)); 10087 PetscFunctionReturn(PETSC_SUCCESS); 10088 } 10089 10090 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10091 { 10092 DM_Plex *plex = (DM_Plex *)dm->data; 10093 PetscSection anchorSection, section, cSec; 10094 Mat cMat; 10095 10096 PetscFunctionBegin; 10097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10098 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10099 if (anchorSection) { 10100 PetscInt Nf; 10101 10102 PetscCall(DMGetLocalSection(dm, §ion)); 10103 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10104 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10105 PetscCall(DMGetNumFields(dm, &Nf)); 10106 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10107 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10108 PetscCall(PetscSectionDestroy(&cSec)); 10109 PetscCall(MatDestroy(&cMat)); 10110 } 10111 PetscFunctionReturn(PETSC_SUCCESS); 10112 } 10113 10114 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10115 { 10116 IS subis; 10117 PetscSection section, subsection; 10118 10119 PetscFunctionBegin; 10120 PetscCall(DMGetLocalSection(dm, §ion)); 10121 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10122 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10123 /* Create subdomain */ 10124 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10125 /* Create submodel */ 10126 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10127 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10128 PetscCall(DMSetLocalSection(*subdm, subsection)); 10129 PetscCall(PetscSectionDestroy(&subsection)); 10130 PetscCall(DMCopyDisc(dm, *subdm)); 10131 /* Create map from submodel to global model */ 10132 if (is) { 10133 PetscSection sectionGlobal, subsectionGlobal; 10134 IS spIS; 10135 const PetscInt *spmap; 10136 PetscInt *subIndices; 10137 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10138 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10139 10140 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10141 PetscCall(ISGetIndices(spIS, &spmap)); 10142 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10143 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10144 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10145 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10146 for (p = pStart; p < pEnd; ++p) { 10147 PetscInt gdof, pSubSize = 0; 10148 10149 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10150 if (gdof > 0) { 10151 for (f = 0; f < Nf; ++f) { 10152 PetscInt fdof, fcdof; 10153 10154 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10155 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10156 pSubSize += fdof - fcdof; 10157 } 10158 subSize += pSubSize; 10159 if (pSubSize) { 10160 if (bs < 0) { 10161 bs = pSubSize; 10162 } else if (bs != pSubSize) { 10163 /* Layout does not admit a pointwise block size */ 10164 bs = 1; 10165 } 10166 } 10167 } 10168 } 10169 /* Must have same blocksize on all procs (some might have no points) */ 10170 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10171 bsLocal[1] = bs; 10172 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10173 if (bsMinMax[0] != bsMinMax[1]) { 10174 bs = 1; 10175 } else { 10176 bs = bsMinMax[0]; 10177 } 10178 PetscCall(PetscMalloc1(subSize, &subIndices)); 10179 for (p = pStart; p < pEnd; ++p) { 10180 PetscInt gdof, goff; 10181 10182 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10183 if (gdof > 0) { 10184 const PetscInt point = spmap[p]; 10185 10186 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10187 for (f = 0; f < Nf; ++f) { 10188 PetscInt fdof, fcdof, fc, f2, poff = 0; 10189 10190 /* Can get rid of this loop by storing field information in the global section */ 10191 for (f2 = 0; f2 < f; ++f2) { 10192 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10193 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10194 poff += fdof - fcdof; 10195 } 10196 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10197 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10198 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10199 } 10200 } 10201 } 10202 PetscCall(ISRestoreIndices(spIS, &spmap)); 10203 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10204 if (bs > 1) { 10205 /* We need to check that the block size does not come from non-contiguous fields */ 10206 PetscInt i, j, set = 1; 10207 for (i = 0; i < subSize; i += bs) { 10208 for (j = 0; j < bs; ++j) { 10209 if (subIndices[i + j] != subIndices[i] + j) { 10210 set = 0; 10211 break; 10212 } 10213 } 10214 } 10215 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10216 } 10217 /* Attach nullspace */ 10218 for (f = 0; f < Nf; ++f) { 10219 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10220 if ((*subdm)->nullspaceConstructors[f]) break; 10221 } 10222 if (f < Nf) { 10223 MatNullSpace nullSpace; 10224 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10225 10226 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10227 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10228 } 10229 } 10230 PetscFunctionReturn(PETSC_SUCCESS); 10231 } 10232 10233 /*@ 10234 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10235 10236 Input Parameters: 10237 + dm - The `DM` 10238 - dummy - unused argument 10239 10240 Options Database Key: 10241 . -dm_plex_monitor_throughput - Activate the monitor 10242 10243 Level: developer 10244 10245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10246 @*/ 10247 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10248 { 10249 PetscLogHandler default_handler; 10250 10251 PetscFunctionBegin; 10252 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10253 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10254 if (default_handler) { 10255 PetscLogEvent event; 10256 PetscEventPerfInfo eventInfo; 10257 PetscReal cellRate, flopRate; 10258 PetscInt cStart, cEnd, Nf, N; 10259 const char *name; 10260 10261 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10262 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10263 PetscCall(DMGetNumFields(dm, &Nf)); 10264 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10265 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10266 N = (cEnd - cStart) * Nf * eventInfo.count; 10267 flopRate = eventInfo.flops / eventInfo.time; 10268 cellRate = N / eventInfo.time; 10269 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))); 10270 } else { 10271 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."); 10272 } 10273 PetscFunctionReturn(PETSC_SUCCESS); 10274 } 10275