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 /* 5457 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5458 representing a line in the section. 5459 */ 5460 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5461 { 5462 PetscFunctionBeginHot; 5463 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5464 if (line < 0) { 5465 *k = 0; 5466 *Nc = 0; 5467 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5468 *k = 1; 5469 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5470 /* An order k SEM disc has k-1 dofs on an edge */ 5471 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5472 *k = *k / *Nc + 1; 5473 } 5474 PetscFunctionReturn(PETSC_SUCCESS); 5475 } 5476 5477 /*@ 5478 5479 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5480 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5481 section provided (or the section of the `DM`). 5482 5483 Input Parameters: 5484 + dm - The `DM` 5485 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5486 - section - The `PetscSection` to reorder, or `NULL` for the default section 5487 5488 Example: 5489 A typical interpolated single-quad mesh might order points as 5490 .vb 5491 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5492 5493 v4 -- e6 -- v3 5494 | | 5495 e7 c0 e8 5496 | | 5497 v1 -- e5 -- v2 5498 .ve 5499 5500 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5501 dofs in the order of points, e.g., 5502 .vb 5503 c0 -> [0,1,2,3] 5504 v1 -> [4] 5505 ... 5506 e5 -> [8, 9] 5507 .ve 5508 5509 which corresponds to the dofs 5510 .vb 5511 6 10 11 7 5512 13 2 3 15 5513 12 0 1 14 5514 4 8 9 5 5515 .ve 5516 5517 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5518 .vb 5519 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5520 .ve 5521 5522 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5523 .vb 5524 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5525 .ve 5526 5527 Level: developer 5528 5529 Notes: 5530 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5531 degree of the basis. 5532 5533 This is required to run with libCEED. 5534 5535 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5536 @*/ 5537 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5538 { 5539 DMLabel label; 5540 PetscInt dim, depth = -1, eStart = -1, Nf; 5541 PetscBool vertexchart; 5542 5543 PetscFunctionBegin; 5544 PetscCall(DMGetDimension(dm, &dim)); 5545 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5546 if (point < 0) { 5547 PetscInt sStart, sEnd; 5548 5549 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5550 point = sEnd - sStart ? sStart : point; 5551 } 5552 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5553 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5554 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5555 if (depth == 1) { 5556 eStart = point; 5557 } else if (depth == dim) { 5558 const PetscInt *cone; 5559 5560 PetscCall(DMPlexGetCone(dm, point, &cone)); 5561 if (dim == 2) eStart = cone[0]; 5562 else if (dim == 3) { 5563 const PetscInt *cone2; 5564 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5565 eStart = cone2[0]; 5566 } 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); 5567 } 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); 5568 { /* Determine whether the chart covers all points or just vertices. */ 5569 PetscInt pStart, pEnd, cStart, cEnd; 5570 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5571 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5572 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5573 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5574 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5575 } 5576 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5577 for (PetscInt d = 1; d <= dim; d++) { 5578 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5579 PetscInt *perm; 5580 5581 for (f = 0; f < Nf; ++f) { 5582 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5583 size += PetscPowInt(k + 1, d) * Nc; 5584 } 5585 PetscCall(PetscMalloc1(size, &perm)); 5586 for (f = 0; f < Nf; ++f) { 5587 switch (d) { 5588 case 1: 5589 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5590 /* 5591 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5592 We want [ vtx0; edge of length k-1; vtx1 ] 5593 */ 5594 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5595 for (i = 0; i < k - 1; i++) 5596 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5597 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5598 foffset = offset; 5599 break; 5600 case 2: 5601 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5602 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5603 /* The SEM order is 5604 5605 v_lb, {e_b}, v_rb, 5606 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5607 v_lt, reverse {e_t}, v_rt 5608 */ 5609 { 5610 const PetscInt of = 0; 5611 const PetscInt oeb = of + PetscSqr(k - 1); 5612 const PetscInt oer = oeb + (k - 1); 5613 const PetscInt oet = oer + (k - 1); 5614 const PetscInt oel = oet + (k - 1); 5615 const PetscInt ovlb = oel + (k - 1); 5616 const PetscInt ovrb = ovlb + 1; 5617 const PetscInt ovrt = ovrb + 1; 5618 const PetscInt ovlt = ovrt + 1; 5619 PetscInt o; 5620 5621 /* bottom */ 5622 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5623 for (o = oeb; o < oer; ++o) 5624 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5625 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5626 /* middle */ 5627 for (i = 0; i < k - 1; ++i) { 5628 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5629 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5630 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5631 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5632 } 5633 /* top */ 5634 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5635 for (o = oel - 1; o >= oet; --o) 5636 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5637 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5638 foffset = offset; 5639 } 5640 break; 5641 case 3: 5642 /* The original hex closure is 5643 5644 {c, 5645 f_b, f_t, f_f, f_b, f_r, f_l, 5646 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5647 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5648 */ 5649 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5650 /* The SEM order is 5651 Bottom Slice 5652 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5653 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5654 v_blb, {e_bb}, v_brb, 5655 5656 Middle Slice (j) 5657 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5658 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5659 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5660 5661 Top Slice 5662 v_tlf, {e_tf}, v_trf, 5663 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5664 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5665 */ 5666 { 5667 const PetscInt oc = 0; 5668 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5669 const PetscInt oft = ofb + PetscSqr(k - 1); 5670 const PetscInt off = oft + PetscSqr(k - 1); 5671 const PetscInt ofk = off + PetscSqr(k - 1); 5672 const PetscInt ofr = ofk + PetscSqr(k - 1); 5673 const PetscInt ofl = ofr + PetscSqr(k - 1); 5674 const PetscInt oebl = ofl + PetscSqr(k - 1); 5675 const PetscInt oebb = oebl + (k - 1); 5676 const PetscInt oebr = oebb + (k - 1); 5677 const PetscInt oebf = oebr + (k - 1); 5678 const PetscInt oetf = oebf + (k - 1); 5679 const PetscInt oetr = oetf + (k - 1); 5680 const PetscInt oetb = oetr + (k - 1); 5681 const PetscInt oetl = oetb + (k - 1); 5682 const PetscInt oerf = oetl + (k - 1); 5683 const PetscInt oelf = oerf + (k - 1); 5684 const PetscInt oelb = oelf + (k - 1); 5685 const PetscInt oerb = oelb + (k - 1); 5686 const PetscInt ovblf = oerb + (k - 1); 5687 const PetscInt ovblb = ovblf + 1; 5688 const PetscInt ovbrb = ovblb + 1; 5689 const PetscInt ovbrf = ovbrb + 1; 5690 const PetscInt ovtlf = ovbrf + 1; 5691 const PetscInt ovtrf = ovtlf + 1; 5692 const PetscInt ovtrb = ovtrf + 1; 5693 const PetscInt ovtlb = ovtrb + 1; 5694 PetscInt o, n; 5695 5696 /* Bottom Slice */ 5697 /* bottom */ 5698 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5699 for (o = oetf - 1; o >= oebf; --o) 5700 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5701 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5702 /* middle */ 5703 for (i = 0; i < k - 1; ++i) { 5704 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5705 for (n = 0; n < k - 1; ++n) { 5706 o = ofb + n * (k - 1) + i; 5707 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5708 } 5709 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5710 } 5711 /* top */ 5712 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5713 for (o = oebb; o < oebr; ++o) 5714 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5715 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5716 5717 /* Middle Slice */ 5718 for (j = 0; j < k - 1; ++j) { 5719 /* bottom */ 5720 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5721 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5722 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5723 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5724 /* middle */ 5725 for (i = 0; i < k - 1; ++i) { 5726 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5727 for (n = 0; n < k - 1; ++n) 5728 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5729 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5730 } 5731 /* top */ 5732 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5733 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5734 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5735 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5736 } 5737 5738 /* Top Slice */ 5739 /* bottom */ 5740 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5741 for (o = oetf; o < oetr; ++o) 5742 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5743 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5744 /* middle */ 5745 for (i = 0; i < k - 1; ++i) { 5746 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5747 for (n = 0; n < k - 1; ++n) 5748 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5749 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5750 } 5751 /* top */ 5752 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5753 for (o = oetl - 1; o >= oetb; --o) 5754 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5755 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5756 5757 foffset = offset; 5758 } 5759 break; 5760 default: 5761 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5762 } 5763 } 5764 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5765 /* Check permutation */ 5766 { 5767 PetscInt *check; 5768 5769 PetscCall(PetscMalloc1(size, &check)); 5770 for (i = 0; i < size; ++i) { 5771 check[i] = -1; 5772 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5773 } 5774 for (i = 0; i < size; ++i) check[perm[i]] = i; 5775 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5776 PetscCall(PetscFree(check)); 5777 } 5778 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5779 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5780 PetscInt *loc_perm; 5781 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5782 for (PetscInt i = 0; i < size; i++) { 5783 loc_perm[i] = perm[i]; 5784 loc_perm[size + i] = size + perm[i]; 5785 } 5786 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5787 } 5788 } 5789 PetscFunctionReturn(PETSC_SUCCESS); 5790 } 5791 5792 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5793 { 5794 PetscDS prob; 5795 PetscInt depth, Nf, h; 5796 DMLabel label; 5797 5798 PetscFunctionBeginHot; 5799 PetscCall(DMGetDS(dm, &prob)); 5800 Nf = prob->Nf; 5801 label = dm->depthLabel; 5802 *dspace = NULL; 5803 if (field < Nf) { 5804 PetscObject disc = prob->disc[field]; 5805 5806 if (disc->classid == PETSCFE_CLASSID) { 5807 PetscDualSpace dsp; 5808 5809 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5810 PetscCall(DMLabelGetNumValues(label, &depth)); 5811 PetscCall(DMLabelGetValue(label, point, &h)); 5812 h = depth - 1 - h; 5813 if (h) { 5814 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5815 } else { 5816 *dspace = dsp; 5817 } 5818 } 5819 } 5820 PetscFunctionReturn(PETSC_SUCCESS); 5821 } 5822 5823 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5824 { 5825 PetscScalar *array; 5826 const PetscScalar *vArray; 5827 const PetscInt *cone, *coneO; 5828 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5829 5830 PetscFunctionBeginHot; 5831 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5832 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5833 PetscCall(DMPlexGetCone(dm, point, &cone)); 5834 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5835 if (!values || !*values) { 5836 if ((point >= pStart) && (point < pEnd)) { 5837 PetscInt dof; 5838 5839 PetscCall(PetscSectionGetDof(section, point, &dof)); 5840 size += dof; 5841 } 5842 for (p = 0; p < numPoints; ++p) { 5843 const PetscInt cp = cone[p]; 5844 PetscInt dof; 5845 5846 if ((cp < pStart) || (cp >= pEnd)) continue; 5847 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5848 size += dof; 5849 } 5850 if (!values) { 5851 if (csize) *csize = size; 5852 PetscFunctionReturn(PETSC_SUCCESS); 5853 } 5854 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5855 } else { 5856 array = *values; 5857 } 5858 size = 0; 5859 PetscCall(VecGetArrayRead(v, &vArray)); 5860 if ((point >= pStart) && (point < pEnd)) { 5861 PetscInt dof, off, d; 5862 const PetscScalar *varr; 5863 5864 PetscCall(PetscSectionGetDof(section, point, &dof)); 5865 PetscCall(PetscSectionGetOffset(section, point, &off)); 5866 varr = &vArray[off]; 5867 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5868 size += dof; 5869 } 5870 for (p = 0; p < numPoints; ++p) { 5871 const PetscInt cp = cone[p]; 5872 PetscInt o = coneO[p]; 5873 PetscInt dof, off, d; 5874 const PetscScalar *varr; 5875 5876 if ((cp < pStart) || (cp >= pEnd)) continue; 5877 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5878 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5879 varr = &vArray[off]; 5880 if (o >= 0) { 5881 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5882 } else { 5883 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5884 } 5885 size += dof; 5886 } 5887 PetscCall(VecRestoreArrayRead(v, &vArray)); 5888 if (!*values) { 5889 if (csize) *csize = size; 5890 *values = array; 5891 } else { 5892 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5893 *csize = size; 5894 } 5895 PetscFunctionReturn(PETSC_SUCCESS); 5896 } 5897 5898 /* Compress out points not in the section */ 5899 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5900 { 5901 const PetscInt np = *numPoints; 5902 PetscInt pStart, pEnd, p, q; 5903 5904 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5905 for (p = 0, q = 0; p < np; ++p) { 5906 const PetscInt r = points[p * 2]; 5907 if ((r >= pStart) && (r < pEnd)) { 5908 points[q * 2] = r; 5909 points[q * 2 + 1] = points[p * 2 + 1]; 5910 ++q; 5911 } 5912 } 5913 *numPoints = q; 5914 return PETSC_SUCCESS; 5915 } 5916 5917 /* Compressed closure does not apply closure permutation */ 5918 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5919 { 5920 const PetscInt *cla = NULL; 5921 PetscInt np, *pts = NULL; 5922 5923 PetscFunctionBeginHot; 5924 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5925 if (!ornt && *clPoints) { 5926 PetscInt dof, off; 5927 5928 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5929 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5930 PetscCall(ISGetIndices(*clPoints, &cla)); 5931 np = dof / 2; 5932 pts = (PetscInt *)&cla[off]; 5933 } else { 5934 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 5935 PetscCall(CompressPoints_Private(section, &np, pts)); 5936 } 5937 *numPoints = np; 5938 *points = pts; 5939 *clp = cla; 5940 PetscFunctionReturn(PETSC_SUCCESS); 5941 } 5942 5943 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5944 { 5945 PetscFunctionBeginHot; 5946 if (!*clPoints) { 5947 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5948 } else { 5949 PetscCall(ISRestoreIndices(*clPoints, clp)); 5950 } 5951 *numPoints = 0; 5952 *points = NULL; 5953 *clSec = NULL; 5954 *clPoints = NULL; 5955 *clp = NULL; 5956 PetscFunctionReturn(PETSC_SUCCESS); 5957 } 5958 5959 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5960 { 5961 PetscInt offset = 0, p; 5962 const PetscInt **perms = NULL; 5963 const PetscScalar **flips = NULL; 5964 5965 PetscFunctionBeginHot; 5966 *size = 0; 5967 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5968 for (p = 0; p < numPoints; p++) { 5969 const PetscInt point = points[2 * p]; 5970 const PetscInt *perm = perms ? perms[p] : NULL; 5971 const PetscScalar *flip = flips ? flips[p] : NULL; 5972 PetscInt dof, off, d; 5973 const PetscScalar *varr; 5974 5975 PetscCall(PetscSectionGetDof(section, point, &dof)); 5976 PetscCall(PetscSectionGetOffset(section, point, &off)); 5977 varr = &vArray[off]; 5978 if (clperm) { 5979 if (perm) { 5980 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5981 } else { 5982 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5983 } 5984 if (flip) { 5985 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5986 } 5987 } else { 5988 if (perm) { 5989 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5990 } else { 5991 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5992 } 5993 if (flip) { 5994 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5995 } 5996 } 5997 offset += dof; 5998 } 5999 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6000 *size = offset; 6001 PetscFunctionReturn(PETSC_SUCCESS); 6002 } 6003 6004 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[]) 6005 { 6006 PetscInt offset = 0, f; 6007 6008 PetscFunctionBeginHot; 6009 *size = 0; 6010 for (f = 0; f < numFields; ++f) { 6011 PetscInt p; 6012 const PetscInt **perms = NULL; 6013 const PetscScalar **flips = NULL; 6014 6015 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6016 for (p = 0; p < numPoints; p++) { 6017 const PetscInt point = points[2 * p]; 6018 PetscInt fdof, foff, b; 6019 const PetscScalar *varr; 6020 const PetscInt *perm = perms ? perms[p] : NULL; 6021 const PetscScalar *flip = flips ? flips[p] : NULL; 6022 6023 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6024 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6025 varr = &vArray[foff]; 6026 if (clperm) { 6027 if (perm) { 6028 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6029 } else { 6030 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6031 } 6032 if (flip) { 6033 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6034 } 6035 } else { 6036 if (perm) { 6037 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6038 } else { 6039 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6040 } 6041 if (flip) { 6042 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6043 } 6044 } 6045 offset += fdof; 6046 } 6047 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6048 } 6049 *size = offset; 6050 PetscFunctionReturn(PETSC_SUCCESS); 6051 } 6052 6053 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6054 { 6055 PetscSection clSection; 6056 IS clPoints; 6057 PetscInt *points = NULL; 6058 const PetscInt *clp, *perm = NULL; 6059 PetscInt depth, numFields, numPoints, asize; 6060 6061 PetscFunctionBeginHot; 6062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6063 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6064 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6065 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6066 PetscCall(DMPlexGetDepth(dm, &depth)); 6067 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6068 if (depth == 1 && numFields < 2) { 6069 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6070 PetscFunctionReturn(PETSC_SUCCESS); 6071 } 6072 /* Get points */ 6073 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6074 /* Get sizes */ 6075 asize = 0; 6076 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6077 PetscInt dof; 6078 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6079 asize += dof; 6080 } 6081 if (values) { 6082 const PetscScalar *vArray; 6083 PetscInt size; 6084 6085 if (*values) { 6086 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); 6087 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6088 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6089 PetscCall(VecGetArrayRead(v, &vArray)); 6090 /* Get values */ 6091 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6092 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6093 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6094 /* Cleanup array */ 6095 PetscCall(VecRestoreArrayRead(v, &vArray)); 6096 } 6097 if (csize) *csize = asize; 6098 /* Cleanup points */ 6099 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6100 PetscFunctionReturn(PETSC_SUCCESS); 6101 } 6102 6103 /*@C 6104 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6105 6106 Not collective 6107 6108 Input Parameters: 6109 + dm - The `DM` 6110 . section - The section describing the layout in `v`, or `NULL` to use the default section 6111 . v - The local vector 6112 - point - The point in the `DM` 6113 6114 Input/Output Parameters: 6115 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6116 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6117 if the user provided `NULL`, it is a borrowed array and should not be freed 6118 6119 Level: intermediate 6120 6121 Notes: 6122 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6123 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6124 assembly function, and a user may already have allocated storage for this operation. 6125 6126 A typical use could be 6127 .vb 6128 values = NULL; 6129 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6130 for (cl = 0; cl < clSize; ++cl) { 6131 <Compute on closure> 6132 } 6133 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6134 .ve 6135 or 6136 .vb 6137 PetscMalloc1(clMaxSize, &values); 6138 for (p = pStart; p < pEnd; ++p) { 6139 clSize = clMaxSize; 6140 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6141 for (cl = 0; cl < clSize; ++cl) { 6142 <Compute on closure> 6143 } 6144 } 6145 PetscFree(values); 6146 .ve 6147 6148 Fortran Notes: 6149 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6150 6151 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6152 @*/ 6153 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6154 { 6155 PetscFunctionBeginHot; 6156 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6157 PetscFunctionReturn(PETSC_SUCCESS); 6158 } 6159 6160 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6161 { 6162 DMLabel depthLabel; 6163 PetscSection clSection; 6164 IS clPoints; 6165 PetscScalar *array; 6166 const PetscScalar *vArray; 6167 PetscInt *points = NULL; 6168 const PetscInt *clp, *perm = NULL; 6169 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6170 6171 PetscFunctionBeginHot; 6172 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6173 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6174 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6175 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6176 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6177 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6178 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6179 if (mdepth == 1 && numFields < 2) { 6180 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6181 PetscFunctionReturn(PETSC_SUCCESS); 6182 } 6183 /* Get points */ 6184 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6185 for (clsize = 0, p = 0; p < Np; p++) { 6186 PetscInt dof; 6187 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6188 clsize += dof; 6189 } 6190 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6191 /* Filter points */ 6192 for (p = 0; p < numPoints * 2; p += 2) { 6193 PetscInt dep; 6194 6195 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6196 if (dep != depth) continue; 6197 points[Np * 2 + 0] = points[p]; 6198 points[Np * 2 + 1] = points[p + 1]; 6199 ++Np; 6200 } 6201 /* Get array */ 6202 if (!values || !*values) { 6203 PetscInt asize = 0, dof; 6204 6205 for (p = 0; p < Np * 2; p += 2) { 6206 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6207 asize += dof; 6208 } 6209 if (!values) { 6210 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6211 if (csize) *csize = asize; 6212 PetscFunctionReturn(PETSC_SUCCESS); 6213 } 6214 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6215 } else { 6216 array = *values; 6217 } 6218 PetscCall(VecGetArrayRead(v, &vArray)); 6219 /* Get values */ 6220 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6221 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6222 /* Cleanup points */ 6223 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6224 /* Cleanup array */ 6225 PetscCall(VecRestoreArrayRead(v, &vArray)); 6226 if (!*values) { 6227 if (csize) *csize = size; 6228 *values = array; 6229 } else { 6230 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6231 *csize = size; 6232 } 6233 PetscFunctionReturn(PETSC_SUCCESS); 6234 } 6235 6236 /*@C 6237 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6238 6239 Not collective 6240 6241 Input Parameters: 6242 + dm - The `DM` 6243 . section - The section describing the layout in `v`, or `NULL` to use the default section 6244 . v - The local vector 6245 . point - The point in the `DM` 6246 . csize - The number of values in the closure, or `NULL` 6247 - values - The array of values, which is a borrowed array and should not be freed 6248 6249 Level: intermediate 6250 6251 Note: 6252 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6253 6254 Fortran Notes: 6255 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6256 6257 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6258 @*/ 6259 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6260 { 6261 PetscInt size = 0; 6262 6263 PetscFunctionBegin; 6264 /* Should work without recalculating size */ 6265 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6266 *values = NULL; 6267 PetscFunctionReturn(PETSC_SUCCESS); 6268 } 6269 6270 static inline void add(PetscScalar *x, PetscScalar y) 6271 { 6272 *x += y; 6273 } 6274 static inline void insert(PetscScalar *x, PetscScalar y) 6275 { 6276 *x = y; 6277 } 6278 6279 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[]) 6280 { 6281 PetscInt cdof; /* The number of constraints on this point */ 6282 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6283 PetscScalar *a; 6284 PetscInt off, cind = 0, k; 6285 6286 PetscFunctionBegin; 6287 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6288 PetscCall(PetscSectionGetOffset(section, point, &off)); 6289 a = &array[off]; 6290 if (!cdof || setBC) { 6291 if (clperm) { 6292 if (perm) { 6293 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6294 } else { 6295 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6296 } 6297 } else { 6298 if (perm) { 6299 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6300 } else { 6301 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6302 } 6303 } 6304 } else { 6305 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6306 if (clperm) { 6307 if (perm) { 6308 for (k = 0; k < dof; ++k) { 6309 if ((cind < cdof) && (k == cdofs[cind])) { 6310 ++cind; 6311 continue; 6312 } 6313 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6314 } 6315 } else { 6316 for (k = 0; k < dof; ++k) { 6317 if ((cind < cdof) && (k == cdofs[cind])) { 6318 ++cind; 6319 continue; 6320 } 6321 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6322 } 6323 } 6324 } else { 6325 if (perm) { 6326 for (k = 0; k < dof; ++k) { 6327 if ((cind < cdof) && (k == cdofs[cind])) { 6328 ++cind; 6329 continue; 6330 } 6331 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6332 } 6333 } else { 6334 for (k = 0; k < dof; ++k) { 6335 if ((cind < cdof) && (k == cdofs[cind])) { 6336 ++cind; 6337 continue; 6338 } 6339 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6340 } 6341 } 6342 } 6343 } 6344 PetscFunctionReturn(PETSC_SUCCESS); 6345 } 6346 6347 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[]) 6348 { 6349 PetscInt cdof; /* The number of constraints on this point */ 6350 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6351 PetscScalar *a; 6352 PetscInt off, cind = 0, k; 6353 6354 PetscFunctionBegin; 6355 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6356 PetscCall(PetscSectionGetOffset(section, point, &off)); 6357 a = &array[off]; 6358 if (cdof) { 6359 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6360 if (clperm) { 6361 if (perm) { 6362 for (k = 0; k < dof; ++k) { 6363 if ((cind < cdof) && (k == cdofs[cind])) { 6364 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6365 cind++; 6366 } 6367 } 6368 } else { 6369 for (k = 0; k < dof; ++k) { 6370 if ((cind < cdof) && (k == cdofs[cind])) { 6371 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6372 cind++; 6373 } 6374 } 6375 } 6376 } else { 6377 if (perm) { 6378 for (k = 0; k < dof; ++k) { 6379 if ((cind < cdof) && (k == cdofs[cind])) { 6380 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6381 cind++; 6382 } 6383 } 6384 } else { 6385 for (k = 0; k < dof; ++k) { 6386 if ((cind < cdof) && (k == cdofs[cind])) { 6387 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6388 cind++; 6389 } 6390 } 6391 } 6392 } 6393 } 6394 PetscFunctionReturn(PETSC_SUCCESS); 6395 } 6396 6397 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[]) 6398 { 6399 PetscScalar *a; 6400 PetscInt fdof, foff, fcdof, foffset = *offset; 6401 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6402 PetscInt cind = 0, b; 6403 6404 PetscFunctionBegin; 6405 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6406 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6407 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6408 a = &array[foff]; 6409 if (!fcdof || setBC) { 6410 if (clperm) { 6411 if (perm) { 6412 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6413 } else { 6414 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6415 } 6416 } else { 6417 if (perm) { 6418 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6419 } else { 6420 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6421 } 6422 } 6423 } else { 6424 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6425 if (clperm) { 6426 if (perm) { 6427 for (b = 0; b < fdof; b++) { 6428 if ((cind < fcdof) && (b == fcdofs[cind])) { 6429 ++cind; 6430 continue; 6431 } 6432 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6433 } 6434 } else { 6435 for (b = 0; b < fdof; b++) { 6436 if ((cind < fcdof) && (b == fcdofs[cind])) { 6437 ++cind; 6438 continue; 6439 } 6440 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6441 } 6442 } 6443 } else { 6444 if (perm) { 6445 for (b = 0; b < fdof; b++) { 6446 if ((cind < fcdof) && (b == fcdofs[cind])) { 6447 ++cind; 6448 continue; 6449 } 6450 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6451 } 6452 } else { 6453 for (b = 0; b < fdof; b++) { 6454 if ((cind < fcdof) && (b == fcdofs[cind])) { 6455 ++cind; 6456 continue; 6457 } 6458 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6459 } 6460 } 6461 } 6462 } 6463 *offset += fdof; 6464 PetscFunctionReturn(PETSC_SUCCESS); 6465 } 6466 6467 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[]) 6468 { 6469 PetscScalar *a; 6470 PetscInt fdof, foff, fcdof, foffset = *offset; 6471 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6472 PetscInt Nc, cind = 0, ncind = 0, b; 6473 PetscBool ncSet, fcSet; 6474 6475 PetscFunctionBegin; 6476 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6477 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6478 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6479 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6480 a = &array[foff]; 6481 if (fcdof) { 6482 /* We just override fcdof and fcdofs with Ncc and comps */ 6483 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6484 if (clperm) { 6485 if (perm) { 6486 if (comps) { 6487 for (b = 0; b < fdof; b++) { 6488 ncSet = fcSet = PETSC_FALSE; 6489 if (b % Nc == comps[ncind]) { 6490 ncind = (ncind + 1) % Ncc; 6491 ncSet = PETSC_TRUE; 6492 } 6493 if ((cind < fcdof) && (b == fcdofs[cind])) { 6494 ++cind; 6495 fcSet = PETSC_TRUE; 6496 } 6497 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6498 } 6499 } else { 6500 for (b = 0; b < fdof; b++) { 6501 if ((cind < fcdof) && (b == fcdofs[cind])) { 6502 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6503 ++cind; 6504 } 6505 } 6506 } 6507 } else { 6508 if (comps) { 6509 for (b = 0; b < fdof; b++) { 6510 ncSet = fcSet = PETSC_FALSE; 6511 if (b % Nc == comps[ncind]) { 6512 ncind = (ncind + 1) % Ncc; 6513 ncSet = PETSC_TRUE; 6514 } 6515 if ((cind < fcdof) && (b == fcdofs[cind])) { 6516 ++cind; 6517 fcSet = PETSC_TRUE; 6518 } 6519 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6520 } 6521 } else { 6522 for (b = 0; b < fdof; b++) { 6523 if ((cind < fcdof) && (b == fcdofs[cind])) { 6524 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6525 ++cind; 6526 } 6527 } 6528 } 6529 } 6530 } else { 6531 if (perm) { 6532 if (comps) { 6533 for (b = 0; b < fdof; b++) { 6534 ncSet = fcSet = PETSC_FALSE; 6535 if (b % Nc == comps[ncind]) { 6536 ncind = (ncind + 1) % Ncc; 6537 ncSet = PETSC_TRUE; 6538 } 6539 if ((cind < fcdof) && (b == fcdofs[cind])) { 6540 ++cind; 6541 fcSet = PETSC_TRUE; 6542 } 6543 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6544 } 6545 } else { 6546 for (b = 0; b < fdof; b++) { 6547 if ((cind < fcdof) && (b == fcdofs[cind])) { 6548 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6549 ++cind; 6550 } 6551 } 6552 } 6553 } else { 6554 if (comps) { 6555 for (b = 0; b < fdof; b++) { 6556 ncSet = fcSet = PETSC_FALSE; 6557 if (b % Nc == comps[ncind]) { 6558 ncind = (ncind + 1) % Ncc; 6559 ncSet = PETSC_TRUE; 6560 } 6561 if ((cind < fcdof) && (b == fcdofs[cind])) { 6562 ++cind; 6563 fcSet = PETSC_TRUE; 6564 } 6565 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6566 } 6567 } else { 6568 for (b = 0; b < fdof; b++) { 6569 if ((cind < fcdof) && (b == fcdofs[cind])) { 6570 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6571 ++cind; 6572 } 6573 } 6574 } 6575 } 6576 } 6577 } 6578 *offset += fdof; 6579 PetscFunctionReturn(PETSC_SUCCESS); 6580 } 6581 6582 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6583 { 6584 PetscScalar *array; 6585 const PetscInt *cone, *coneO; 6586 PetscInt pStart, pEnd, p, numPoints, off, dof; 6587 6588 PetscFunctionBeginHot; 6589 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6590 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6591 PetscCall(DMPlexGetCone(dm, point, &cone)); 6592 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6593 PetscCall(VecGetArray(v, &array)); 6594 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6595 const PetscInt cp = !p ? point : cone[p - 1]; 6596 const PetscInt o = !p ? 0 : coneO[p - 1]; 6597 6598 if ((cp < pStart) || (cp >= pEnd)) { 6599 dof = 0; 6600 continue; 6601 } 6602 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6603 /* ADD_VALUES */ 6604 { 6605 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6606 PetscScalar *a; 6607 PetscInt cdof, coff, cind = 0, k; 6608 6609 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6610 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6611 a = &array[coff]; 6612 if (!cdof) { 6613 if (o >= 0) { 6614 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6615 } else { 6616 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6617 } 6618 } else { 6619 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6620 if (o >= 0) { 6621 for (k = 0; k < dof; ++k) { 6622 if ((cind < cdof) && (k == cdofs[cind])) { 6623 ++cind; 6624 continue; 6625 } 6626 a[k] += values[off + k]; 6627 } 6628 } else { 6629 for (k = 0; k < dof; ++k) { 6630 if ((cind < cdof) && (k == cdofs[cind])) { 6631 ++cind; 6632 continue; 6633 } 6634 a[k] += values[off + dof - k - 1]; 6635 } 6636 } 6637 } 6638 } 6639 } 6640 PetscCall(VecRestoreArray(v, &array)); 6641 PetscFunctionReturn(PETSC_SUCCESS); 6642 } 6643 6644 /*@C 6645 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6646 6647 Not collective 6648 6649 Input Parameters: 6650 + dm - The `DM` 6651 . section - The section describing the layout in `v`, or `NULL` to use the default section 6652 . v - The local vector 6653 . point - The point in the `DM` 6654 . values - The array of values 6655 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6656 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6657 6658 Level: intermediate 6659 6660 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6661 @*/ 6662 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6663 { 6664 PetscSection clSection; 6665 IS clPoints; 6666 PetscScalar *array; 6667 PetscInt *points = NULL; 6668 const PetscInt *clp, *clperm = NULL; 6669 PetscInt depth, numFields, numPoints, p, clsize; 6670 6671 PetscFunctionBeginHot; 6672 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6673 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6674 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6675 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6676 PetscCall(DMPlexGetDepth(dm, &depth)); 6677 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6678 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6679 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6680 PetscFunctionReturn(PETSC_SUCCESS); 6681 } 6682 /* Get points */ 6683 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6684 for (clsize = 0, p = 0; p < numPoints; p++) { 6685 PetscInt dof; 6686 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6687 clsize += dof; 6688 } 6689 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6690 /* Get array */ 6691 PetscCall(VecGetArray(v, &array)); 6692 /* Get values */ 6693 if (numFields > 0) { 6694 PetscInt offset = 0, f; 6695 for (f = 0; f < numFields; ++f) { 6696 const PetscInt **perms = NULL; 6697 const PetscScalar **flips = NULL; 6698 6699 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6700 switch (mode) { 6701 case INSERT_VALUES: 6702 for (p = 0; p < numPoints; p++) { 6703 const PetscInt point = points[2 * p]; 6704 const PetscInt *perm = perms ? perms[p] : NULL; 6705 const PetscScalar *flip = flips ? flips[p] : NULL; 6706 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6707 } 6708 break; 6709 case INSERT_ALL_VALUES: 6710 for (p = 0; p < numPoints; p++) { 6711 const PetscInt point = points[2 * p]; 6712 const PetscInt *perm = perms ? perms[p] : NULL; 6713 const PetscScalar *flip = flips ? flips[p] : NULL; 6714 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6715 } 6716 break; 6717 case INSERT_BC_VALUES: 6718 for (p = 0; p < numPoints; p++) { 6719 const PetscInt point = points[2 * p]; 6720 const PetscInt *perm = perms ? perms[p] : NULL; 6721 const PetscScalar *flip = flips ? flips[p] : NULL; 6722 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6723 } 6724 break; 6725 case ADD_VALUES: 6726 for (p = 0; p < numPoints; p++) { 6727 const PetscInt point = points[2 * p]; 6728 const PetscInt *perm = perms ? perms[p] : NULL; 6729 const PetscScalar *flip = flips ? flips[p] : NULL; 6730 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6731 } 6732 break; 6733 case ADD_ALL_VALUES: 6734 for (p = 0; p < numPoints; p++) { 6735 const PetscInt point = points[2 * p]; 6736 const PetscInt *perm = perms ? perms[p] : NULL; 6737 const PetscScalar *flip = flips ? flips[p] : NULL; 6738 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6739 } 6740 break; 6741 case ADD_BC_VALUES: 6742 for (p = 0; p < numPoints; p++) { 6743 const PetscInt point = points[2 * p]; 6744 const PetscInt *perm = perms ? perms[p] : NULL; 6745 const PetscScalar *flip = flips ? flips[p] : NULL; 6746 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6747 } 6748 break; 6749 default: 6750 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6751 } 6752 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6753 } 6754 } else { 6755 PetscInt dof, off; 6756 const PetscInt **perms = NULL; 6757 const PetscScalar **flips = NULL; 6758 6759 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6760 switch (mode) { 6761 case INSERT_VALUES: 6762 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6763 const PetscInt point = points[2 * p]; 6764 const PetscInt *perm = perms ? perms[p] : NULL; 6765 const PetscScalar *flip = flips ? flips[p] : NULL; 6766 PetscCall(PetscSectionGetDof(section, point, &dof)); 6767 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6768 } 6769 break; 6770 case INSERT_ALL_VALUES: 6771 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6772 const PetscInt point = points[2 * p]; 6773 const PetscInt *perm = perms ? perms[p] : NULL; 6774 const PetscScalar *flip = flips ? flips[p] : NULL; 6775 PetscCall(PetscSectionGetDof(section, point, &dof)); 6776 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6777 } 6778 break; 6779 case INSERT_BC_VALUES: 6780 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6781 const PetscInt point = points[2 * p]; 6782 const PetscInt *perm = perms ? perms[p] : NULL; 6783 const PetscScalar *flip = flips ? flips[p] : NULL; 6784 PetscCall(PetscSectionGetDof(section, point, &dof)); 6785 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6786 } 6787 break; 6788 case ADD_VALUES: 6789 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6790 const PetscInt point = points[2 * p]; 6791 const PetscInt *perm = perms ? perms[p] : NULL; 6792 const PetscScalar *flip = flips ? flips[p] : NULL; 6793 PetscCall(PetscSectionGetDof(section, point, &dof)); 6794 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6795 } 6796 break; 6797 case ADD_ALL_VALUES: 6798 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6799 const PetscInt point = points[2 * p]; 6800 const PetscInt *perm = perms ? perms[p] : NULL; 6801 const PetscScalar *flip = flips ? flips[p] : NULL; 6802 PetscCall(PetscSectionGetDof(section, point, &dof)); 6803 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6804 } 6805 break; 6806 case ADD_BC_VALUES: 6807 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6808 const PetscInt point = points[2 * p]; 6809 const PetscInt *perm = perms ? perms[p] : NULL; 6810 const PetscScalar *flip = flips ? flips[p] : NULL; 6811 PetscCall(PetscSectionGetDof(section, point, &dof)); 6812 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6813 } 6814 break; 6815 default: 6816 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6817 } 6818 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6819 } 6820 /* Cleanup points */ 6821 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6822 /* Cleanup array */ 6823 PetscCall(VecRestoreArray(v, &array)); 6824 PetscFunctionReturn(PETSC_SUCCESS); 6825 } 6826 6827 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6828 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6829 { 6830 PetscFunctionBegin; 6831 *contains = PETSC_TRUE; 6832 if (label) { 6833 PetscInt fdof; 6834 6835 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6836 if (!*contains) { 6837 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6838 *offset += fdof; 6839 PetscFunctionReturn(PETSC_SUCCESS); 6840 } 6841 } 6842 PetscFunctionReturn(PETSC_SUCCESS); 6843 } 6844 6845 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6846 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) 6847 { 6848 PetscSection clSection; 6849 IS clPoints; 6850 PetscScalar *array; 6851 PetscInt *points = NULL; 6852 const PetscInt *clp; 6853 PetscInt numFields, numPoints, p; 6854 PetscInt offset = 0, f; 6855 6856 PetscFunctionBeginHot; 6857 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6858 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6859 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6860 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6861 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6862 /* Get points */ 6863 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6864 /* Get array */ 6865 PetscCall(VecGetArray(v, &array)); 6866 /* Get values */ 6867 for (f = 0; f < numFields; ++f) { 6868 const PetscInt **perms = NULL; 6869 const PetscScalar **flips = NULL; 6870 PetscBool contains; 6871 6872 if (!fieldActive[f]) { 6873 for (p = 0; p < numPoints * 2; p += 2) { 6874 PetscInt fdof; 6875 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6876 offset += fdof; 6877 } 6878 continue; 6879 } 6880 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6881 switch (mode) { 6882 case INSERT_VALUES: 6883 for (p = 0; p < numPoints; p++) { 6884 const PetscInt point = points[2 * p]; 6885 const PetscInt *perm = perms ? perms[p] : NULL; 6886 const PetscScalar *flip = flips ? flips[p] : NULL; 6887 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6888 if (!contains) continue; 6889 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6890 } 6891 break; 6892 case INSERT_ALL_VALUES: 6893 for (p = 0; p < numPoints; p++) { 6894 const PetscInt point = points[2 * p]; 6895 const PetscInt *perm = perms ? perms[p] : NULL; 6896 const PetscScalar *flip = flips ? flips[p] : NULL; 6897 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6898 if (!contains) continue; 6899 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6900 } 6901 break; 6902 case INSERT_BC_VALUES: 6903 for (p = 0; p < numPoints; p++) { 6904 const PetscInt point = points[2 * p]; 6905 const PetscInt *perm = perms ? perms[p] : NULL; 6906 const PetscScalar *flip = flips ? flips[p] : NULL; 6907 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6908 if (!contains) continue; 6909 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6910 } 6911 break; 6912 case ADD_VALUES: 6913 for (p = 0; p < numPoints; p++) { 6914 const PetscInt point = points[2 * p]; 6915 const PetscInt *perm = perms ? perms[p] : NULL; 6916 const PetscScalar *flip = flips ? flips[p] : NULL; 6917 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6918 if (!contains) continue; 6919 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6920 } 6921 break; 6922 case ADD_ALL_VALUES: 6923 for (p = 0; p < numPoints; p++) { 6924 const PetscInt point = points[2 * p]; 6925 const PetscInt *perm = perms ? perms[p] : NULL; 6926 const PetscScalar *flip = flips ? flips[p] : NULL; 6927 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6928 if (!contains) continue; 6929 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6930 } 6931 break; 6932 default: 6933 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6934 } 6935 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6936 } 6937 /* Cleanup points */ 6938 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6939 /* Cleanup array */ 6940 PetscCall(VecRestoreArray(v, &array)); 6941 PetscFunctionReturn(PETSC_SUCCESS); 6942 } 6943 6944 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6945 { 6946 PetscMPIInt rank; 6947 PetscInt i, j; 6948 6949 PetscFunctionBegin; 6950 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6951 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6952 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6953 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6954 numCIndices = numCIndices ? numCIndices : numRIndices; 6955 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 6956 for (i = 0; i < numRIndices; i++) { 6957 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6958 for (j = 0; j < numCIndices; j++) { 6959 #if defined(PETSC_USE_COMPLEX) 6960 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6961 #else 6962 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6963 #endif 6964 } 6965 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6966 } 6967 PetscFunctionReturn(PETSC_SUCCESS); 6968 } 6969 6970 /* 6971 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6972 6973 Input Parameters: 6974 + section - The section for this data layout 6975 . islocal - Is the section (and thus indices being requested) local or global? 6976 . point - The point contributing dofs with these indices 6977 . off - The global offset of this point 6978 . loff - The local offset of each field 6979 . setBC - The flag determining whether to include indices of boundary values 6980 . perm - A permutation of the dofs on this point, or NULL 6981 - indperm - A permutation of the entire indices array, or NULL 6982 6983 Output Parameter: 6984 . indices - Indices for dofs on this point 6985 6986 Level: developer 6987 6988 Note: The indices could be local or global, depending on the value of 'off'. 6989 */ 6990 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6991 { 6992 PetscInt dof; /* The number of unknowns on this point */ 6993 PetscInt cdof; /* The number of constraints on this point */ 6994 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6995 PetscInt cind = 0, k; 6996 6997 PetscFunctionBegin; 6998 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6999 PetscCall(PetscSectionGetDof(section, point, &dof)); 7000 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7001 if (!cdof || setBC) { 7002 for (k = 0; k < dof; ++k) { 7003 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7004 const PetscInt ind = indperm ? indperm[preind] : preind; 7005 7006 indices[ind] = off + k; 7007 } 7008 } else { 7009 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7010 for (k = 0; k < dof; ++k) { 7011 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7012 const PetscInt ind = indperm ? indperm[preind] : preind; 7013 7014 if ((cind < cdof) && (k == cdofs[cind])) { 7015 /* Insert check for returning constrained indices */ 7016 indices[ind] = -(off + k + 1); 7017 ++cind; 7018 } else { 7019 indices[ind] = off + k - (islocal ? 0 : cind); 7020 } 7021 } 7022 } 7023 *loff += dof; 7024 PetscFunctionReturn(PETSC_SUCCESS); 7025 } 7026 7027 /* 7028 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7029 7030 Input Parameters: 7031 + section - a section (global or local) 7032 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7033 . point - point within section 7034 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7035 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7036 . setBC - identify constrained (boundary condition) points via involution. 7037 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7038 . permsoff - offset 7039 - indperm - index permutation 7040 7041 Output Parameter: 7042 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7043 . indices - array to hold indices (as defined by section) of each dof associated with point 7044 7045 Notes: 7046 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7047 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7048 in the local vector. 7049 7050 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7051 significant). It is invalid to call with a global section and setBC=true. 7052 7053 Developer Note: 7054 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7055 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7056 offset could be obtained from the section instead of passing it explicitly as we do now. 7057 7058 Example: 7059 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7060 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7061 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7062 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. 7063 7064 Level: developer 7065 */ 7066 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[]) 7067 { 7068 PetscInt numFields, foff, f; 7069 7070 PetscFunctionBegin; 7071 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7072 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7073 for (f = 0, foff = 0; f < numFields; ++f) { 7074 PetscInt fdof, cfdof; 7075 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7076 PetscInt cind = 0, b; 7077 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7078 7079 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7080 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7081 if (!cfdof || setBC) { 7082 for (b = 0; b < fdof; ++b) { 7083 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7084 const PetscInt ind = indperm ? indperm[preind] : preind; 7085 7086 indices[ind] = off + foff + b; 7087 } 7088 } else { 7089 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7090 for (b = 0; b < fdof; ++b) { 7091 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7092 const PetscInt ind = indperm ? indperm[preind] : preind; 7093 7094 if ((cind < cfdof) && (b == fcdofs[cind])) { 7095 indices[ind] = -(off + foff + b + 1); 7096 ++cind; 7097 } else { 7098 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7099 } 7100 } 7101 } 7102 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7103 foffs[f] += fdof; 7104 } 7105 PetscFunctionReturn(PETSC_SUCCESS); 7106 } 7107 7108 /* 7109 This version believes the globalSection offsets for each field, rather than just the point offset 7110 7111 . foffs - The offset into 'indices' for each field, since it is segregated by field 7112 7113 Notes: 7114 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7115 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7116 */ 7117 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7118 { 7119 PetscInt numFields, foff, f; 7120 7121 PetscFunctionBegin; 7122 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7123 for (f = 0; f < numFields; ++f) { 7124 PetscInt fdof, cfdof; 7125 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7126 PetscInt cind = 0, b; 7127 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7128 7129 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7130 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7131 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7132 if (!cfdof) { 7133 for (b = 0; b < fdof; ++b) { 7134 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7135 const PetscInt ind = indperm ? indperm[preind] : preind; 7136 7137 indices[ind] = foff + b; 7138 } 7139 } else { 7140 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7141 for (b = 0; b < fdof; ++b) { 7142 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7143 const PetscInt ind = indperm ? indperm[preind] : preind; 7144 7145 if ((cind < cfdof) && (b == fcdofs[cind])) { 7146 indices[ind] = -(foff + b + 1); 7147 ++cind; 7148 } else { 7149 indices[ind] = foff + b - cind; 7150 } 7151 } 7152 } 7153 foffs[f] += fdof; 7154 } 7155 PetscFunctionReturn(PETSC_SUCCESS); 7156 } 7157 7158 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) 7159 { 7160 Mat cMat; 7161 PetscSection aSec, cSec; 7162 IS aIS; 7163 PetscInt aStart = -1, aEnd = -1; 7164 const PetscInt *anchors; 7165 PetscInt numFields, f, p, q, newP = 0; 7166 PetscInt newNumPoints = 0, newNumIndices = 0; 7167 PetscInt *newPoints, *indices, *newIndices; 7168 PetscInt maxAnchor, maxDof; 7169 PetscInt newOffsets[32]; 7170 PetscInt *pointMatOffsets[32]; 7171 PetscInt *newPointOffsets[32]; 7172 PetscScalar *pointMat[32]; 7173 PetscScalar *newValues = NULL, *tmpValues; 7174 PetscBool anyConstrained = PETSC_FALSE; 7175 7176 PetscFunctionBegin; 7177 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7178 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7179 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7180 7181 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7182 /* if there are point-to-point constraints */ 7183 if (aSec) { 7184 PetscCall(PetscArrayzero(newOffsets, 32)); 7185 PetscCall(ISGetIndices(aIS, &anchors)); 7186 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7187 /* figure out how many points are going to be in the new element matrix 7188 * (we allow double counting, because it's all just going to be summed 7189 * into the global matrix anyway) */ 7190 for (p = 0; p < 2 * numPoints; p += 2) { 7191 PetscInt b = points[p]; 7192 PetscInt bDof = 0, bSecDof; 7193 7194 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7195 if (!bSecDof) continue; 7196 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7197 if (bDof) { 7198 /* this point is constrained */ 7199 /* it is going to be replaced by its anchors */ 7200 PetscInt bOff, q; 7201 7202 anyConstrained = PETSC_TRUE; 7203 newNumPoints += bDof; 7204 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7205 for (q = 0; q < bDof; q++) { 7206 PetscInt a = anchors[bOff + q]; 7207 PetscInt aDof; 7208 7209 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7210 newNumIndices += aDof; 7211 for (f = 0; f < numFields; ++f) { 7212 PetscInt fDof; 7213 7214 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7215 newOffsets[f + 1] += fDof; 7216 } 7217 } 7218 } else { 7219 /* this point is not constrained */ 7220 newNumPoints++; 7221 newNumIndices += bSecDof; 7222 for (f = 0; f < numFields; ++f) { 7223 PetscInt fDof; 7224 7225 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7226 newOffsets[f + 1] += fDof; 7227 } 7228 } 7229 } 7230 } 7231 if (!anyConstrained) { 7232 if (outNumPoints) *outNumPoints = 0; 7233 if (outNumIndices) *outNumIndices = 0; 7234 if (outPoints) *outPoints = NULL; 7235 if (outValues) *outValues = NULL; 7236 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7237 PetscFunctionReturn(PETSC_SUCCESS); 7238 } 7239 7240 if (outNumPoints) *outNumPoints = newNumPoints; 7241 if (outNumIndices) *outNumIndices = newNumIndices; 7242 7243 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7244 7245 if (!outPoints && !outValues) { 7246 if (offsets) { 7247 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7248 } 7249 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7250 PetscFunctionReturn(PETSC_SUCCESS); 7251 } 7252 7253 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7254 7255 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7256 7257 /* workspaces */ 7258 if (numFields) { 7259 for (f = 0; f < numFields; f++) { 7260 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7261 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7262 } 7263 } else { 7264 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7265 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7266 } 7267 7268 /* get workspaces for the point-to-point matrices */ 7269 if (numFields) { 7270 PetscInt totalOffset, totalMatOffset; 7271 7272 for (p = 0; p < numPoints; p++) { 7273 PetscInt b = points[2 * p]; 7274 PetscInt bDof = 0, bSecDof; 7275 7276 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7277 if (!bSecDof) { 7278 for (f = 0; f < numFields; f++) { 7279 newPointOffsets[f][p + 1] = 0; 7280 pointMatOffsets[f][p + 1] = 0; 7281 } 7282 continue; 7283 } 7284 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7285 if (bDof) { 7286 for (f = 0; f < numFields; f++) { 7287 PetscInt fDof, q, bOff, allFDof = 0; 7288 7289 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7290 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7291 for (q = 0; q < bDof; q++) { 7292 PetscInt a = anchors[bOff + q]; 7293 PetscInt aFDof; 7294 7295 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7296 allFDof += aFDof; 7297 } 7298 newPointOffsets[f][p + 1] = allFDof; 7299 pointMatOffsets[f][p + 1] = fDof * allFDof; 7300 } 7301 } else { 7302 for (f = 0; f < numFields; f++) { 7303 PetscInt fDof; 7304 7305 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7306 newPointOffsets[f][p + 1] = fDof; 7307 pointMatOffsets[f][p + 1] = 0; 7308 } 7309 } 7310 } 7311 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7312 newPointOffsets[f][0] = totalOffset; 7313 pointMatOffsets[f][0] = totalMatOffset; 7314 for (p = 0; p < numPoints; p++) { 7315 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7316 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7317 } 7318 totalOffset = newPointOffsets[f][numPoints]; 7319 totalMatOffset = pointMatOffsets[f][numPoints]; 7320 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7321 } 7322 } else { 7323 for (p = 0; p < numPoints; p++) { 7324 PetscInt b = points[2 * p]; 7325 PetscInt bDof = 0, bSecDof; 7326 7327 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7328 if (!bSecDof) { 7329 newPointOffsets[0][p + 1] = 0; 7330 pointMatOffsets[0][p + 1] = 0; 7331 continue; 7332 } 7333 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7334 if (bDof) { 7335 PetscInt bOff, q, allDof = 0; 7336 7337 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7338 for (q = 0; q < bDof; q++) { 7339 PetscInt a = anchors[bOff + q], aDof; 7340 7341 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7342 allDof += aDof; 7343 } 7344 newPointOffsets[0][p + 1] = allDof; 7345 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7346 } else { 7347 newPointOffsets[0][p + 1] = bSecDof; 7348 pointMatOffsets[0][p + 1] = 0; 7349 } 7350 } 7351 newPointOffsets[0][0] = 0; 7352 pointMatOffsets[0][0] = 0; 7353 for (p = 0; p < numPoints; p++) { 7354 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7355 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7356 } 7357 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7358 } 7359 7360 /* output arrays */ 7361 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7362 7363 /* get the point-to-point matrices; construct newPoints */ 7364 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7365 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7366 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7367 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7368 if (numFields) { 7369 for (p = 0, newP = 0; p < numPoints; p++) { 7370 PetscInt b = points[2 * p]; 7371 PetscInt o = points[2 * p + 1]; 7372 PetscInt bDof = 0, bSecDof; 7373 7374 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7375 if (!bSecDof) continue; 7376 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7377 if (bDof) { 7378 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7379 7380 fStart[0] = 0; 7381 fEnd[0] = 0; 7382 for (f = 0; f < numFields; f++) { 7383 PetscInt fDof; 7384 7385 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7386 fStart[f + 1] = fStart[f] + fDof; 7387 fEnd[f + 1] = fStart[f + 1]; 7388 } 7389 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7390 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7391 7392 fAnchorStart[0] = 0; 7393 fAnchorEnd[0] = 0; 7394 for (f = 0; f < numFields; f++) { 7395 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7396 7397 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7398 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7399 } 7400 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7401 for (q = 0; q < bDof; q++) { 7402 PetscInt a = anchors[bOff + q], aOff; 7403 7404 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7405 newPoints[2 * (newP + q)] = a; 7406 newPoints[2 * (newP + q) + 1] = 0; 7407 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7408 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7409 } 7410 newP += bDof; 7411 7412 if (outValues) { 7413 /* get the point-to-point submatrix */ 7414 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])); 7415 } 7416 } else { 7417 newPoints[2 * newP] = b; 7418 newPoints[2 * newP + 1] = o; 7419 newP++; 7420 } 7421 } 7422 } else { 7423 for (p = 0; p < numPoints; p++) { 7424 PetscInt b = points[2 * p]; 7425 PetscInt o = points[2 * p + 1]; 7426 PetscInt bDof = 0, bSecDof; 7427 7428 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7429 if (!bSecDof) continue; 7430 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7431 if (bDof) { 7432 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7433 7434 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7435 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7436 7437 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7438 for (q = 0; q < bDof; q++) { 7439 PetscInt a = anchors[bOff + q], aOff; 7440 7441 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7442 7443 newPoints[2 * (newP + q)] = a; 7444 newPoints[2 * (newP + q) + 1] = 0; 7445 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7446 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7447 } 7448 newP += bDof; 7449 7450 /* get the point-to-point submatrix */ 7451 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7452 } else { 7453 newPoints[2 * newP] = b; 7454 newPoints[2 * newP + 1] = o; 7455 newP++; 7456 } 7457 } 7458 } 7459 7460 if (outValues) { 7461 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7462 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7463 /* multiply constraints on the right */ 7464 if (numFields) { 7465 for (f = 0; f < numFields; f++) { 7466 PetscInt oldOff = offsets[f]; 7467 7468 for (p = 0; p < numPoints; p++) { 7469 PetscInt cStart = newPointOffsets[f][p]; 7470 PetscInt b = points[2 * p]; 7471 PetscInt c, r, k; 7472 PetscInt dof; 7473 7474 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7475 if (!dof) continue; 7476 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7477 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7478 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7479 7480 for (r = 0; r < numIndices; r++) { 7481 for (c = 0; c < nCols; c++) { 7482 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7483 } 7484 } 7485 } else { 7486 /* copy this column as is */ 7487 for (r = 0; r < numIndices; r++) { 7488 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7489 } 7490 } 7491 oldOff += dof; 7492 } 7493 } 7494 } else { 7495 PetscInt oldOff = 0; 7496 for (p = 0; p < numPoints; p++) { 7497 PetscInt cStart = newPointOffsets[0][p]; 7498 PetscInt b = points[2 * p]; 7499 PetscInt c, r, k; 7500 PetscInt dof; 7501 7502 PetscCall(PetscSectionGetDof(section, b, &dof)); 7503 if (!dof) continue; 7504 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7505 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7506 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7507 7508 for (r = 0; r < numIndices; r++) { 7509 for (c = 0; c < nCols; c++) { 7510 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7511 } 7512 } 7513 } else { 7514 /* copy this column as is */ 7515 for (r = 0; r < numIndices; r++) { 7516 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7517 } 7518 } 7519 oldOff += dof; 7520 } 7521 } 7522 7523 if (multiplyLeft) { 7524 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7525 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7526 /* multiply constraints transpose on the left */ 7527 if (numFields) { 7528 for (f = 0; f < numFields; f++) { 7529 PetscInt oldOff = offsets[f]; 7530 7531 for (p = 0; p < numPoints; p++) { 7532 PetscInt rStart = newPointOffsets[f][p]; 7533 PetscInt b = points[2 * p]; 7534 PetscInt c, r, k; 7535 PetscInt dof; 7536 7537 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7538 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7539 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7540 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7541 7542 for (r = 0; r < nRows; r++) { 7543 for (c = 0; c < newNumIndices; c++) { 7544 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7545 } 7546 } 7547 } else { 7548 /* copy this row as is */ 7549 for (r = 0; r < dof; r++) { 7550 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7551 } 7552 } 7553 oldOff += dof; 7554 } 7555 } 7556 } else { 7557 PetscInt oldOff = 0; 7558 7559 for (p = 0; p < numPoints; p++) { 7560 PetscInt rStart = newPointOffsets[0][p]; 7561 PetscInt b = points[2 * p]; 7562 PetscInt c, r, k; 7563 PetscInt dof; 7564 7565 PetscCall(PetscSectionGetDof(section, b, &dof)); 7566 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7567 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7568 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7569 7570 for (r = 0; r < nRows; r++) { 7571 for (c = 0; c < newNumIndices; c++) { 7572 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7573 } 7574 } 7575 } else { 7576 /* copy this row as is */ 7577 for (r = 0; r < dof; r++) { 7578 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7579 } 7580 } 7581 oldOff += dof; 7582 } 7583 } 7584 7585 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7586 } else { 7587 newValues = tmpValues; 7588 } 7589 } 7590 7591 /* clean up */ 7592 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7593 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7594 7595 if (numFields) { 7596 for (f = 0; f < numFields; f++) { 7597 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7598 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7599 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7600 } 7601 } else { 7602 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7603 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7604 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7605 } 7606 PetscCall(ISRestoreIndices(aIS, &anchors)); 7607 7608 /* output */ 7609 if (outPoints) { 7610 *outPoints = newPoints; 7611 } else { 7612 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7613 } 7614 if (outValues) *outValues = newValues; 7615 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7616 PetscFunctionReturn(PETSC_SUCCESS); 7617 } 7618 7619 /*@C 7620 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7621 7622 Not collective 7623 7624 Input Parameters: 7625 + dm - The `DM` 7626 . section - The `PetscSection` describing the points (a local section) 7627 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7628 . point - The point defining the closure 7629 - useClPerm - Use the closure point permutation if available 7630 7631 Output Parameters: 7632 + numIndices - The number of dof indices in the closure of point with the input sections 7633 . indices - The dof indices 7634 . outOffsets - Array to write the field offsets into, or `NULL` 7635 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7636 7637 Level: advanced 7638 7639 Notes: 7640 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7641 7642 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7643 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7644 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7645 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7646 indices (with the above semantics) are implied. 7647 7648 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7649 `PetscSection`, `DMGetGlobalSection()` 7650 @*/ 7651 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7652 { 7653 /* Closure ordering */ 7654 PetscSection clSection; 7655 IS clPoints; 7656 const PetscInt *clp; 7657 PetscInt *points; 7658 const PetscInt *clperm = NULL; 7659 /* Dof permutation and sign flips */ 7660 const PetscInt **perms[32] = {NULL}; 7661 const PetscScalar **flips[32] = {NULL}; 7662 PetscScalar *valCopy = NULL; 7663 /* Hanging node constraints */ 7664 PetscInt *pointsC = NULL; 7665 PetscScalar *valuesC = NULL; 7666 PetscInt NclC, NiC; 7667 7668 PetscInt *idx; 7669 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7670 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7671 7672 PetscFunctionBeginHot; 7673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7674 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7675 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7676 if (numIndices) PetscAssertPointer(numIndices, 6); 7677 if (indices) PetscAssertPointer(indices, 7); 7678 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7679 if (values) PetscAssertPointer(values, 9); 7680 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7681 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7682 PetscCall(PetscArrayzero(offsets, 32)); 7683 /* 1) Get points in closure */ 7684 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7685 if (useClPerm) { 7686 PetscInt depth, clsize; 7687 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7688 for (clsize = 0, p = 0; p < Ncl; p++) { 7689 PetscInt dof; 7690 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7691 clsize += dof; 7692 } 7693 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7694 } 7695 /* 2) Get number of indices on these points and field offsets from section */ 7696 for (p = 0; p < Ncl * 2; p += 2) { 7697 PetscInt dof, fdof; 7698 7699 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7700 for (f = 0; f < Nf; ++f) { 7701 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7702 offsets[f + 1] += fdof; 7703 } 7704 Ni += dof; 7705 } 7706 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7707 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7708 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7709 for (f = 0; f < PetscMax(1, Nf); ++f) { 7710 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7711 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7712 /* may need to apply sign changes to the element matrix */ 7713 if (values && flips[f]) { 7714 PetscInt foffset = offsets[f]; 7715 7716 for (p = 0; p < Ncl; ++p) { 7717 PetscInt pnt = points[2 * p], fdof; 7718 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7719 7720 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7721 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7722 if (flip) { 7723 PetscInt i, j, k; 7724 7725 if (!valCopy) { 7726 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7727 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7728 *values = valCopy; 7729 } 7730 for (i = 0; i < fdof; ++i) { 7731 PetscScalar fval = flip[i]; 7732 7733 for (k = 0; k < Ni; ++k) { 7734 valCopy[Ni * (foffset + i) + k] *= fval; 7735 valCopy[Ni * k + (foffset + i)] *= fval; 7736 } 7737 } 7738 } 7739 foffset += fdof; 7740 } 7741 } 7742 } 7743 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7744 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7745 if (NclC) { 7746 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7747 for (f = 0; f < PetscMax(1, Nf); ++f) { 7748 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7749 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7750 } 7751 for (f = 0; f < PetscMax(1, Nf); ++f) { 7752 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7753 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7754 } 7755 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7756 Ncl = NclC; 7757 Ni = NiC; 7758 points = pointsC; 7759 if (values) *values = valuesC; 7760 } 7761 /* 5) Calculate indices */ 7762 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7763 if (Nf) { 7764 PetscInt idxOff; 7765 PetscBool useFieldOffsets; 7766 7767 if (outOffsets) { 7768 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7769 } 7770 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7771 if (useFieldOffsets) { 7772 for (p = 0; p < Ncl; ++p) { 7773 const PetscInt pnt = points[p * 2]; 7774 7775 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7776 } 7777 } else { 7778 for (p = 0; p < Ncl; ++p) { 7779 const PetscInt pnt = points[p * 2]; 7780 7781 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7782 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7783 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7784 * global section. */ 7785 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7786 } 7787 } 7788 } else { 7789 PetscInt off = 0, idxOff; 7790 7791 for (p = 0; p < Ncl; ++p) { 7792 const PetscInt pnt = points[p * 2]; 7793 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7794 7795 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7796 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7797 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7798 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7799 } 7800 } 7801 /* 6) Cleanup */ 7802 for (f = 0; f < PetscMax(1, Nf); ++f) { 7803 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7804 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7805 } 7806 if (NclC) { 7807 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7808 } else { 7809 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7810 } 7811 7812 if (numIndices) *numIndices = Ni; 7813 if (indices) *indices = idx; 7814 PetscFunctionReturn(PETSC_SUCCESS); 7815 } 7816 7817 /*@C 7818 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7819 7820 Not collective 7821 7822 Input Parameters: 7823 + dm - The `DM` 7824 . section - The `PetscSection` describing the points (a local section) 7825 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7826 . point - The point defining the closure 7827 - useClPerm - Use the closure point permutation if available 7828 7829 Output Parameters: 7830 + numIndices - The number of dof indices in the closure of point with the input sections 7831 . indices - The dof indices 7832 . outOffsets - Array to write the field offsets into, or `NULL` 7833 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7834 7835 Level: advanced 7836 7837 Notes: 7838 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7839 7840 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7841 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7842 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7843 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7844 indices (with the above semantics) are implied. 7845 7846 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7847 @*/ 7848 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7849 { 7850 PetscFunctionBegin; 7851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7852 PetscAssertPointer(indices, 7); 7853 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7854 PetscFunctionReturn(PETSC_SUCCESS); 7855 } 7856 7857 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7858 { 7859 DM_Plex *mesh = (DM_Plex *)dm->data; 7860 PetscInt *indices; 7861 PetscInt numIndices; 7862 const PetscScalar *valuesOrig = values; 7863 PetscErrorCode ierr; 7864 7865 PetscFunctionBegin; 7866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7867 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7868 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7869 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7870 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7871 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 7872 7873 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7874 7875 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7876 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7877 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7878 if (ierr) { 7879 PetscMPIInt rank; 7880 7881 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7882 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7883 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7884 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7885 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7886 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7887 } 7888 if (mesh->printFEM > 1) { 7889 PetscInt i; 7890 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7891 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7892 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7893 } 7894 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 PetscFunctionReturn(PETSC_SUCCESS); 7898 } 7899 7900 /*@C 7901 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7902 7903 Not collective 7904 7905 Input Parameters: 7906 + dm - The `DM` 7907 . section - The section describing the layout in `v`, or `NULL` to use the default section 7908 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 7909 . A - The matrix 7910 . point - The point in the `DM` 7911 . values - The array of values 7912 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7913 7914 Level: intermediate 7915 7916 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7917 @*/ 7918 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7919 { 7920 PetscFunctionBegin; 7921 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 7922 PetscFunctionReturn(PETSC_SUCCESS); 7923 } 7924 7925 /*@C 7926 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 7927 7928 Not collective 7929 7930 Input Parameters: 7931 + dmRow - The `DM` for the row fields 7932 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 7933 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 7934 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 7935 . dmCol - The `DM` for the column fields 7936 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 7937 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 7938 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 7939 . A - The matrix 7940 . point - The point in the `DM` 7941 . values - The array of values 7942 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7943 7944 Level: intermediate 7945 7946 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7947 @*/ 7948 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) 7949 { 7950 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7951 PetscInt *indicesRow, *indicesCol; 7952 PetscInt numIndicesRow, numIndicesCol; 7953 const PetscScalar *valuesOrig = values; 7954 PetscErrorCode ierr; 7955 7956 PetscFunctionBegin; 7957 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7958 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7959 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7960 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7961 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7962 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 7963 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7964 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 7965 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7966 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 7967 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 7968 7969 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7970 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7971 7972 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7973 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7974 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7975 if (ierr) { 7976 PetscMPIInt rank; 7977 7978 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7979 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7980 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7981 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7982 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7983 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7984 } 7985 7986 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7987 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7988 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7989 PetscFunctionReturn(PETSC_SUCCESS); 7990 } 7991 7992 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7993 { 7994 DM_Plex *mesh = (DM_Plex *)dmf->data; 7995 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7996 PetscInt *cpoints = NULL; 7997 PetscInt *findices, *cindices; 7998 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7999 PetscInt foffsets[32], coffsets[32]; 8000 DMPolytopeType ct; 8001 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8002 PetscErrorCode ierr; 8003 8004 PetscFunctionBegin; 8005 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8006 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8007 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8008 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8009 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8010 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8011 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8012 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8013 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8014 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8015 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8016 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8017 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8018 PetscCall(PetscArrayzero(foffsets, 32)); 8019 PetscCall(PetscArrayzero(coffsets, 32)); 8020 /* Column indices */ 8021 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8022 maxFPoints = numCPoints; 8023 /* Compress out points not in the section */ 8024 /* TODO: Squeeze out points with 0 dof as well */ 8025 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8026 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8027 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8028 cpoints[q * 2] = cpoints[p]; 8029 cpoints[q * 2 + 1] = cpoints[p + 1]; 8030 ++q; 8031 } 8032 } 8033 numCPoints = q; 8034 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8035 PetscInt fdof; 8036 8037 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8038 if (!dof) continue; 8039 for (f = 0; f < numFields; ++f) { 8040 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8041 coffsets[f + 1] += fdof; 8042 } 8043 numCIndices += dof; 8044 } 8045 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8046 /* Row indices */ 8047 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8048 { 8049 DMPlexTransform tr; 8050 DMPolytopeType *rct; 8051 PetscInt *rsize, *rcone, *rornt, Nt; 8052 8053 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8054 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8055 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8056 numSubcells = rsize[Nt - 1]; 8057 PetscCall(DMPlexTransformDestroy(&tr)); 8058 } 8059 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8060 for (r = 0, q = 0; r < numSubcells; ++r) { 8061 /* TODO Map from coarse to fine cells */ 8062 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8063 /* Compress out points not in the section */ 8064 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8065 for (p = 0; p < numFPoints * 2; p += 2) { 8066 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8067 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8068 if (!dof) continue; 8069 for (s = 0; s < q; ++s) 8070 if (fpoints[p] == ftotpoints[s * 2]) break; 8071 if (s < q) continue; 8072 ftotpoints[q * 2] = fpoints[p]; 8073 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8074 ++q; 8075 } 8076 } 8077 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8078 } 8079 numFPoints = q; 8080 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8081 PetscInt fdof; 8082 8083 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8084 if (!dof) continue; 8085 for (f = 0; f < numFields; ++f) { 8086 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8087 foffsets[f + 1] += fdof; 8088 } 8089 numFIndices += dof; 8090 } 8091 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8092 8093 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8094 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8095 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8096 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8097 if (numFields) { 8098 const PetscInt **permsF[32] = {NULL}; 8099 const PetscInt **permsC[32] = {NULL}; 8100 8101 for (f = 0; f < numFields; f++) { 8102 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8103 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8104 } 8105 for (p = 0; p < numFPoints; p++) { 8106 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8107 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8108 } 8109 for (p = 0; p < numCPoints; p++) { 8110 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8111 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8112 } 8113 for (f = 0; f < numFields; f++) { 8114 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8115 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8116 } 8117 } else { 8118 const PetscInt **permsF = NULL; 8119 const PetscInt **permsC = NULL; 8120 8121 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8122 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8123 for (p = 0, off = 0; p < numFPoints; p++) { 8124 const PetscInt *perm = permsF ? permsF[p] : NULL; 8125 8126 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8127 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8128 } 8129 for (p = 0, off = 0; p < numCPoints; p++) { 8130 const PetscInt *perm = permsC ? permsC[p] : NULL; 8131 8132 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8133 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8134 } 8135 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8136 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8137 } 8138 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8139 /* TODO: flips */ 8140 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8141 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8142 if (ierr) { 8143 PetscMPIInt rank; 8144 8145 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8146 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8147 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8148 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8149 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8150 } 8151 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8152 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8153 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8154 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8155 PetscFunctionReturn(PETSC_SUCCESS); 8156 } 8157 8158 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8159 { 8160 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8161 PetscInt *cpoints = NULL; 8162 PetscInt foffsets[32], coffsets[32]; 8163 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8164 DMPolytopeType ct; 8165 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8166 8167 PetscFunctionBegin; 8168 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8169 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8170 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8171 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8172 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8173 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8174 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8175 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8176 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8177 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8178 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8179 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8180 PetscCall(PetscArrayzero(foffsets, 32)); 8181 PetscCall(PetscArrayzero(coffsets, 32)); 8182 /* Column indices */ 8183 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8184 maxFPoints = numCPoints; 8185 /* Compress out points not in the section */ 8186 /* TODO: Squeeze out points with 0 dof as well */ 8187 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8188 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8189 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8190 cpoints[q * 2] = cpoints[p]; 8191 cpoints[q * 2 + 1] = cpoints[p + 1]; 8192 ++q; 8193 } 8194 } 8195 numCPoints = q; 8196 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8197 PetscInt fdof; 8198 8199 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8200 if (!dof) continue; 8201 for (f = 0; f < numFields; ++f) { 8202 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8203 coffsets[f + 1] += fdof; 8204 } 8205 numCIndices += dof; 8206 } 8207 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8208 /* Row indices */ 8209 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8210 { 8211 DMPlexTransform tr; 8212 DMPolytopeType *rct; 8213 PetscInt *rsize, *rcone, *rornt, Nt; 8214 8215 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8216 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8217 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8218 numSubcells = rsize[Nt - 1]; 8219 PetscCall(DMPlexTransformDestroy(&tr)); 8220 } 8221 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8222 for (r = 0, q = 0; r < numSubcells; ++r) { 8223 /* TODO Map from coarse to fine cells */ 8224 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8225 /* Compress out points not in the section */ 8226 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8227 for (p = 0; p < numFPoints * 2; p += 2) { 8228 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8229 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8230 if (!dof) continue; 8231 for (s = 0; s < q; ++s) 8232 if (fpoints[p] == ftotpoints[s * 2]) break; 8233 if (s < q) continue; 8234 ftotpoints[q * 2] = fpoints[p]; 8235 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8236 ++q; 8237 } 8238 } 8239 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8240 } 8241 numFPoints = q; 8242 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8243 PetscInt fdof; 8244 8245 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8246 if (!dof) continue; 8247 for (f = 0; f < numFields; ++f) { 8248 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8249 foffsets[f + 1] += fdof; 8250 } 8251 numFIndices += dof; 8252 } 8253 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8254 8255 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8256 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8257 if (numFields) { 8258 const PetscInt **permsF[32] = {NULL}; 8259 const PetscInt **permsC[32] = {NULL}; 8260 8261 for (f = 0; f < numFields; f++) { 8262 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8263 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8264 } 8265 for (p = 0; p < numFPoints; p++) { 8266 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8267 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8268 } 8269 for (p = 0; p < numCPoints; p++) { 8270 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8271 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8272 } 8273 for (f = 0; f < numFields; f++) { 8274 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8275 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8276 } 8277 } else { 8278 const PetscInt **permsF = NULL; 8279 const PetscInt **permsC = NULL; 8280 8281 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8282 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8283 for (p = 0, off = 0; p < numFPoints; p++) { 8284 const PetscInt *perm = permsF ? permsF[p] : NULL; 8285 8286 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8287 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8288 } 8289 for (p = 0, off = 0; p < numCPoints; p++) { 8290 const PetscInt *perm = permsC ? permsC[p] : NULL; 8291 8292 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8293 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8294 } 8295 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8296 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8297 } 8298 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8299 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8300 PetscFunctionReturn(PETSC_SUCCESS); 8301 } 8302 8303 /*@C 8304 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8305 8306 Input Parameter: 8307 . dm - The `DMPLEX` object 8308 8309 Output Parameter: 8310 . cellHeight - The height of a cell 8311 8312 Level: developer 8313 8314 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8315 @*/ 8316 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8317 { 8318 DM_Plex *mesh = (DM_Plex *)dm->data; 8319 8320 PetscFunctionBegin; 8321 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8322 PetscAssertPointer(cellHeight, 2); 8323 *cellHeight = mesh->vtkCellHeight; 8324 PetscFunctionReturn(PETSC_SUCCESS); 8325 } 8326 8327 /*@C 8328 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8329 8330 Input Parameters: 8331 + dm - The `DMPLEX` object 8332 - cellHeight - The height of a cell 8333 8334 Level: developer 8335 8336 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8337 @*/ 8338 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8339 { 8340 DM_Plex *mesh = (DM_Plex *)dm->data; 8341 8342 PetscFunctionBegin; 8343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8344 mesh->vtkCellHeight = cellHeight; 8345 PetscFunctionReturn(PETSC_SUCCESS); 8346 } 8347 8348 /*@ 8349 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8350 8351 Input Parameters: 8352 + dm - The `DMPLEX` object 8353 - ct - The `DMPolytopeType` of the cell 8354 8355 Output Parameters: 8356 + start - The first cell of this type, or `NULL` 8357 - end - The upper bound on this celltype, or `NULL` 8358 8359 Level: advanced 8360 8361 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8362 @*/ 8363 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8364 { 8365 DM_Plex *mesh = (DM_Plex *)dm->data; 8366 DMLabel label; 8367 PetscInt pStart, pEnd; 8368 8369 PetscFunctionBegin; 8370 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8371 if (start) { 8372 PetscAssertPointer(start, 3); 8373 *start = 0; 8374 } 8375 if (end) { 8376 PetscAssertPointer(end, 4); 8377 *end = 0; 8378 } 8379 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8380 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8381 if (mesh->tr) { 8382 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8383 } else { 8384 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8385 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8386 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8387 } 8388 PetscFunctionReturn(PETSC_SUCCESS); 8389 } 8390 8391 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8392 { 8393 PetscSection section, globalSection; 8394 PetscInt *numbers, p; 8395 8396 PetscFunctionBegin; 8397 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8398 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8399 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8400 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8401 PetscCall(PetscSectionSetUp(section)); 8402 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8403 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8404 for (p = pStart; p < pEnd; ++p) { 8405 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8406 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8407 else numbers[p - pStart] += shift; 8408 } 8409 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8410 if (globalSize) { 8411 PetscLayout layout; 8412 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8413 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8414 PetscCall(PetscLayoutDestroy(&layout)); 8415 } 8416 PetscCall(PetscSectionDestroy(§ion)); 8417 PetscCall(PetscSectionDestroy(&globalSection)); 8418 PetscFunctionReturn(PETSC_SUCCESS); 8419 } 8420 8421 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8422 { 8423 PetscInt cellHeight, cStart, cEnd; 8424 8425 PetscFunctionBegin; 8426 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8427 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8428 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8429 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8430 PetscFunctionReturn(PETSC_SUCCESS); 8431 } 8432 8433 /*@ 8434 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8435 8436 Input Parameter: 8437 . dm - The `DMPLEX` object 8438 8439 Output Parameter: 8440 . globalCellNumbers - Global cell numbers for all cells on this process 8441 8442 Level: developer 8443 8444 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8445 @*/ 8446 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8447 { 8448 DM_Plex *mesh = (DM_Plex *)dm->data; 8449 8450 PetscFunctionBegin; 8451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8452 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8453 *globalCellNumbers = mesh->globalCellNumbers; 8454 PetscFunctionReturn(PETSC_SUCCESS); 8455 } 8456 8457 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8458 { 8459 PetscInt vStart, vEnd; 8460 8461 PetscFunctionBegin; 8462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8463 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8464 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8465 PetscFunctionReturn(PETSC_SUCCESS); 8466 } 8467 8468 /*@ 8469 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8470 8471 Input Parameter: 8472 . dm - The `DMPLEX` object 8473 8474 Output Parameter: 8475 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8476 8477 Level: developer 8478 8479 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8480 @*/ 8481 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8482 { 8483 DM_Plex *mesh = (DM_Plex *)dm->data; 8484 8485 PetscFunctionBegin; 8486 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8487 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8488 *globalVertexNumbers = mesh->globalVertexNumbers; 8489 PetscFunctionReturn(PETSC_SUCCESS); 8490 } 8491 8492 /*@ 8493 DMPlexCreatePointNumbering - Create a global numbering for all points. 8494 8495 Collective 8496 8497 Input Parameter: 8498 . dm - The `DMPLEX` object 8499 8500 Output Parameter: 8501 . globalPointNumbers - Global numbers for all points on this process 8502 8503 Level: developer 8504 8505 Notes: 8506 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8507 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8508 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8509 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8510 8511 The partitioned mesh is 8512 ``` 8513 (2)--0--(3)--1--(4) (1)--0--(2) 8514 ``` 8515 and its global numbering is 8516 ``` 8517 (3)--0--(4)--1--(5)--2--(6) 8518 ``` 8519 Then the global numbering is provided as 8520 ``` 8521 [0] Number of indices in set 5 8522 [0] 0 0 8523 [0] 1 1 8524 [0] 2 3 8525 [0] 3 4 8526 [0] 4 -6 8527 [1] Number of indices in set 3 8528 [1] 0 2 8529 [1] 1 5 8530 [1] 2 6 8531 ``` 8532 8533 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8534 @*/ 8535 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8536 { 8537 IS nums[4]; 8538 PetscInt depths[4], gdepths[4], starts[4]; 8539 PetscInt depth, d, shift = 0; 8540 PetscBool empty = PETSC_FALSE; 8541 8542 PetscFunctionBegin; 8543 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8544 PetscCall(DMPlexGetDepth(dm, &depth)); 8545 // For unstratified meshes use dim instead of depth 8546 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8547 // If any stratum is empty, we must mark all empty 8548 for (d = 0; d <= depth; ++d) { 8549 PetscInt end; 8550 8551 depths[d] = depth - d; 8552 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8553 if (!(starts[d] - end)) empty = PETSC_TRUE; 8554 } 8555 if (empty) 8556 for (d = 0; d <= depth; ++d) { 8557 depths[d] = -1; 8558 starts[d] = -1; 8559 } 8560 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8561 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8562 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]); 8563 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8564 for (d = 0; d <= depth; ++d) { 8565 PetscInt pStart, pEnd, gsize; 8566 8567 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8568 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8569 shift += gsize; 8570 } 8571 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8572 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8573 PetscFunctionReturn(PETSC_SUCCESS); 8574 } 8575 8576 /*@ 8577 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8578 8579 Input Parameter: 8580 . dm - The `DMPLEX` object 8581 8582 Output Parameter: 8583 . ranks - The rank field 8584 8585 Options Database Key: 8586 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8587 8588 Level: intermediate 8589 8590 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8591 @*/ 8592 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8593 { 8594 DM rdm; 8595 PetscFE fe; 8596 PetscScalar *r; 8597 PetscMPIInt rank; 8598 DMPolytopeType ct; 8599 PetscInt dim, cStart, cEnd, c; 8600 PetscBool simplex; 8601 8602 PetscFunctionBeginUser; 8603 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8604 PetscAssertPointer(ranks, 2); 8605 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8606 PetscCall(DMClone(dm, &rdm)); 8607 PetscCall(DMGetDimension(rdm, &dim)); 8608 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8609 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8610 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8611 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8612 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8613 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8614 PetscCall(PetscFEDestroy(&fe)); 8615 PetscCall(DMCreateDS(rdm)); 8616 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8617 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8618 PetscCall(VecGetArray(*ranks, &r)); 8619 for (c = cStart; c < cEnd; ++c) { 8620 PetscScalar *lr; 8621 8622 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8623 if (lr) *lr = rank; 8624 } 8625 PetscCall(VecRestoreArray(*ranks, &r)); 8626 PetscCall(DMDestroy(&rdm)); 8627 PetscFunctionReturn(PETSC_SUCCESS); 8628 } 8629 8630 /*@ 8631 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8632 8633 Input Parameters: 8634 + dm - The `DMPLEX` 8635 - label - The `DMLabel` 8636 8637 Output Parameter: 8638 . val - The label value field 8639 8640 Options Database Key: 8641 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8642 8643 Level: intermediate 8644 8645 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8646 @*/ 8647 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8648 { 8649 DM rdm; 8650 PetscFE fe; 8651 PetscScalar *v; 8652 PetscInt dim, cStart, cEnd, c; 8653 8654 PetscFunctionBeginUser; 8655 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8656 PetscAssertPointer(label, 2); 8657 PetscAssertPointer(val, 3); 8658 PetscCall(DMClone(dm, &rdm)); 8659 PetscCall(DMGetDimension(rdm, &dim)); 8660 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8661 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8662 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8663 PetscCall(PetscFEDestroy(&fe)); 8664 PetscCall(DMCreateDS(rdm)); 8665 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8666 PetscCall(DMCreateGlobalVector(rdm, val)); 8667 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8668 PetscCall(VecGetArray(*val, &v)); 8669 for (c = cStart; c < cEnd; ++c) { 8670 PetscScalar *lv; 8671 PetscInt cval; 8672 8673 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8674 PetscCall(DMLabelGetValue(label, c, &cval)); 8675 *lv = cval; 8676 } 8677 PetscCall(VecRestoreArray(*val, &v)); 8678 PetscCall(DMDestroy(&rdm)); 8679 PetscFunctionReturn(PETSC_SUCCESS); 8680 } 8681 8682 /*@ 8683 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8684 8685 Input Parameter: 8686 . dm - The `DMPLEX` object 8687 8688 Level: developer 8689 8690 Notes: 8691 This is a useful diagnostic when creating meshes programmatically. 8692 8693 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8694 8695 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8696 @*/ 8697 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8698 { 8699 PetscSection coneSection, supportSection; 8700 const PetscInt *cone, *support; 8701 PetscInt coneSize, c, supportSize, s; 8702 PetscInt pStart, pEnd, p, pp, csize, ssize; 8703 PetscBool storagecheck = PETSC_TRUE; 8704 8705 PetscFunctionBegin; 8706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8707 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8708 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8709 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8710 /* Check that point p is found in the support of its cone points, and vice versa */ 8711 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8712 for (p = pStart; p < pEnd; ++p) { 8713 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8714 PetscCall(DMPlexGetCone(dm, p, &cone)); 8715 for (c = 0; c < coneSize; ++c) { 8716 PetscBool dup = PETSC_FALSE; 8717 PetscInt d; 8718 for (d = c - 1; d >= 0; --d) { 8719 if (cone[c] == cone[d]) { 8720 dup = PETSC_TRUE; 8721 break; 8722 } 8723 } 8724 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8725 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8726 for (s = 0; s < supportSize; ++s) { 8727 if (support[s] == p) break; 8728 } 8729 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8730 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8731 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8732 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8733 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8734 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8735 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8736 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]); 8737 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8738 } 8739 } 8740 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8741 if (p != pp) { 8742 storagecheck = PETSC_FALSE; 8743 continue; 8744 } 8745 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8746 PetscCall(DMPlexGetSupport(dm, p, &support)); 8747 for (s = 0; s < supportSize; ++s) { 8748 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8749 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8750 for (c = 0; c < coneSize; ++c) { 8751 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8752 if (cone[c] != pp) { 8753 c = 0; 8754 break; 8755 } 8756 if (cone[c] == p) break; 8757 } 8758 if (c >= coneSize) { 8759 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8760 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8761 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8762 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8763 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8764 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8765 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8766 } 8767 } 8768 } 8769 if (storagecheck) { 8770 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8771 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8772 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8773 } 8774 PetscFunctionReturn(PETSC_SUCCESS); 8775 } 8776 8777 /* 8778 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. 8779 */ 8780 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8781 { 8782 DMPolytopeType cct; 8783 PetscInt ptpoints[4]; 8784 const PetscInt *cone, *ccone, *ptcone; 8785 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8786 8787 PetscFunctionBegin; 8788 *unsplit = 0; 8789 switch (ct) { 8790 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8791 ptpoints[npt++] = c; 8792 break; 8793 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8794 PetscCall(DMPlexGetCone(dm, c, &cone)); 8795 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8796 for (cp = 0; cp < coneSize; ++cp) { 8797 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8798 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8799 } 8800 break; 8801 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8802 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8803 PetscCall(DMPlexGetCone(dm, c, &cone)); 8804 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8805 for (cp = 0; cp < coneSize; ++cp) { 8806 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8807 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8808 for (ccp = 0; ccp < cconeSize; ++ccp) { 8809 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8810 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8811 PetscInt p; 8812 for (p = 0; p < npt; ++p) 8813 if (ptpoints[p] == ccone[ccp]) break; 8814 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8815 } 8816 } 8817 } 8818 break; 8819 default: 8820 break; 8821 } 8822 for (pt = 0; pt < npt; ++pt) { 8823 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8824 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8825 } 8826 PetscFunctionReturn(PETSC_SUCCESS); 8827 } 8828 8829 /*@ 8830 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8831 8832 Input Parameters: 8833 + dm - The `DMPLEX` object 8834 - cellHeight - Normally 0 8835 8836 Level: developer 8837 8838 Notes: 8839 This is a useful diagnostic when creating meshes programmatically. 8840 Currently applicable only to homogeneous simplex or tensor meshes. 8841 8842 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8843 8844 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8845 @*/ 8846 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8847 { 8848 DMPlexInterpolatedFlag interp; 8849 DMPolytopeType ct; 8850 PetscInt vStart, vEnd, cStart, cEnd, c; 8851 8852 PetscFunctionBegin; 8853 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8854 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8855 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8856 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8857 for (c = cStart; c < cEnd; ++c) { 8858 PetscInt *closure = NULL; 8859 PetscInt coneSize, closureSize, cl, Nv = 0; 8860 8861 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8862 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8863 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8864 if (interp == DMPLEX_INTERPOLATED_FULL) { 8865 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8866 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)); 8867 } 8868 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8869 for (cl = 0; cl < closureSize * 2; cl += 2) { 8870 const PetscInt p = closure[cl]; 8871 if ((p >= vStart) && (p < vEnd)) ++Nv; 8872 } 8873 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8874 /* Special Case: Tensor faces with identified vertices */ 8875 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8876 PetscInt unsplit; 8877 8878 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8879 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8880 } 8881 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)); 8882 } 8883 PetscFunctionReturn(PETSC_SUCCESS); 8884 } 8885 8886 /*@ 8887 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8888 8889 Collective 8890 8891 Input Parameters: 8892 + dm - The `DMPLEX` object 8893 - cellHeight - Normally 0 8894 8895 Level: developer 8896 8897 Notes: 8898 This is a useful diagnostic when creating meshes programmatically. 8899 This routine is only relevant for meshes that are fully interpolated across all ranks. 8900 It will error out if a partially interpolated mesh is given on some rank. 8901 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8902 8903 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8904 8905 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8906 @*/ 8907 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8908 { 8909 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8910 DMPlexInterpolatedFlag interpEnum; 8911 8912 PetscFunctionBegin; 8913 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8914 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8915 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 8916 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8917 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 8918 PetscFunctionReturn(PETSC_SUCCESS); 8919 } 8920 8921 PetscCall(DMGetDimension(dm, &dim)); 8922 PetscCall(DMPlexGetDepth(dm, &depth)); 8923 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8924 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8925 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8926 for (c = cStart; c < cEnd; ++c) { 8927 const PetscInt *cone, *ornt, *faceSizes, *faces; 8928 const DMPolytopeType *faceTypes; 8929 DMPolytopeType ct; 8930 PetscInt numFaces, coneSize, f; 8931 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8932 8933 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8934 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8935 if (unsplit) continue; 8936 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8937 PetscCall(DMPlexGetCone(dm, c, &cone)); 8938 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8939 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8940 for (cl = 0; cl < closureSize * 2; cl += 2) { 8941 const PetscInt p = closure[cl]; 8942 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8943 } 8944 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8945 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); 8946 for (f = 0; f < numFaces; ++f) { 8947 DMPolytopeType fct; 8948 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8949 8950 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8951 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8952 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8953 const PetscInt p = fclosure[cl]; 8954 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8955 } 8956 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]); 8957 for (v = 0; v < fnumCorners; ++v) { 8958 if (fclosure[v] != faces[fOff + v]) { 8959 PetscInt v1; 8960 8961 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8962 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8963 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8964 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8965 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8966 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]); 8967 } 8968 } 8969 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8970 fOff += faceSizes[f]; 8971 } 8972 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8973 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8974 } 8975 } 8976 PetscFunctionReturn(PETSC_SUCCESS); 8977 } 8978 8979 /*@ 8980 DMPlexCheckGeometry - Check the geometry of mesh cells 8981 8982 Input Parameter: 8983 . dm - The `DMPLEX` object 8984 8985 Level: developer 8986 8987 Notes: 8988 This is a useful diagnostic when creating meshes programmatically. 8989 8990 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8991 8992 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8993 @*/ 8994 PetscErrorCode DMPlexCheckGeometry(DM dm) 8995 { 8996 Vec coordinates; 8997 PetscReal detJ, J[9], refVol = 1.0; 8998 PetscReal vol; 8999 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9000 9001 PetscFunctionBegin; 9002 PetscCall(DMGetDimension(dm, &dim)); 9003 PetscCall(DMGetCoordinateDim(dm, &dE)); 9004 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9005 PetscCall(DMPlexGetDepth(dm, &depth)); 9006 for (d = 0; d < dim; ++d) refVol *= 2.0; 9007 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9008 /* Make sure local coordinates are created, because that step is collective */ 9009 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9010 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9011 for (c = cStart; c < cEnd; ++c) { 9012 DMPolytopeType ct; 9013 PetscInt unsplit; 9014 PetscBool ignoreZeroVol = PETSC_FALSE; 9015 9016 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9017 switch (ct) { 9018 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9019 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9020 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9021 ignoreZeroVol = PETSC_TRUE; 9022 break; 9023 default: 9024 break; 9025 } 9026 switch (ct) { 9027 case DM_POLYTOPE_TRI_PRISM: 9028 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9029 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9030 case DM_POLYTOPE_PYRAMID: 9031 continue; 9032 default: 9033 break; 9034 } 9035 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9036 if (unsplit) continue; 9037 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9038 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); 9039 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9040 /* This should work with periodicity since DG coordinates should be used */ 9041 if (depth > 1) { 9042 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9043 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); 9044 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9045 } 9046 } 9047 PetscFunctionReturn(PETSC_SUCCESS); 9048 } 9049 9050 /*@ 9051 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9052 9053 Collective 9054 9055 Input Parameters: 9056 + dm - The `DMPLEX` object 9057 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9058 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9059 9060 Level: developer 9061 9062 Notes: 9063 This is mainly intended for debugging/testing purposes. 9064 9065 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9066 9067 Extra roots can come from periodic cuts, where additional points appear on the boundary 9068 9069 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9070 @*/ 9071 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9072 { 9073 PetscInt l, nleaves, nroots, overlap; 9074 const PetscInt *locals; 9075 const PetscSFNode *remotes; 9076 PetscBool distributed; 9077 MPI_Comm comm; 9078 PetscMPIInt rank; 9079 9080 PetscFunctionBegin; 9081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9082 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9083 else pointSF = dm->sf; 9084 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9085 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9086 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9087 { 9088 PetscMPIInt mpiFlag; 9089 9090 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9091 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9092 } 9093 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9094 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9095 if (!distributed) { 9096 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); 9097 PetscFunctionReturn(PETSC_SUCCESS); 9098 } 9099 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); 9100 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9101 9102 /* Check SF graph is compatible with DMPlex chart */ 9103 { 9104 PetscInt pStart, pEnd, maxLeaf; 9105 9106 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9107 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9108 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9109 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9110 } 9111 9112 /* Check Point SF has no local points referenced */ 9113 for (l = 0; l < nleaves; l++) { 9114 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); 9115 } 9116 9117 /* Check there are no cells in interface */ 9118 if (!overlap) { 9119 PetscInt cellHeight, cStart, cEnd; 9120 9121 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9122 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9123 for (l = 0; l < nleaves; ++l) { 9124 const PetscInt point = locals ? locals[l] : l; 9125 9126 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9127 } 9128 } 9129 9130 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9131 { 9132 const PetscInt *rootdegree; 9133 9134 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9135 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9136 for (l = 0; l < nleaves; ++l) { 9137 const PetscInt point = locals ? locals[l] : l; 9138 const PetscInt *cone; 9139 PetscInt coneSize, c, idx; 9140 9141 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9142 PetscCall(DMPlexGetCone(dm, point, &cone)); 9143 for (c = 0; c < coneSize; ++c) { 9144 if (!rootdegree[cone[c]]) { 9145 if (locals) { 9146 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9147 } else { 9148 idx = (cone[c] < nleaves) ? cone[c] : -1; 9149 } 9150 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9151 } 9152 } 9153 } 9154 } 9155 PetscFunctionReturn(PETSC_SUCCESS); 9156 } 9157 9158 /*@ 9159 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9160 9161 Input Parameter: 9162 . dm - The `DMPLEX` object 9163 9164 Level: developer 9165 9166 Notes: 9167 This is a useful diagnostic when creating meshes programmatically. 9168 9169 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9170 9171 Currently does not include `DMPlexCheckCellShape()`. 9172 9173 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9174 @*/ 9175 PetscErrorCode DMPlexCheck(DM dm) 9176 { 9177 PetscInt cellHeight; 9178 9179 PetscFunctionBegin; 9180 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9181 PetscCall(DMPlexCheckSymmetry(dm)); 9182 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9183 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9184 PetscCall(DMPlexCheckGeometry(dm)); 9185 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9186 PetscCall(DMPlexCheckInterfaceCones(dm)); 9187 PetscFunctionReturn(PETSC_SUCCESS); 9188 } 9189 9190 typedef struct cell_stats { 9191 PetscReal min, max, sum, squaresum; 9192 PetscInt count; 9193 } cell_stats_t; 9194 9195 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9196 { 9197 PetscInt i, N = *len; 9198 9199 for (i = 0; i < N; i++) { 9200 cell_stats_t *A = (cell_stats_t *)a; 9201 cell_stats_t *B = (cell_stats_t *)b; 9202 9203 B->min = PetscMin(A->min, B->min); 9204 B->max = PetscMax(A->max, B->max); 9205 B->sum += A->sum; 9206 B->squaresum += A->squaresum; 9207 B->count += A->count; 9208 } 9209 } 9210 9211 /*@ 9212 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9213 9214 Collective 9215 9216 Input Parameters: 9217 + dm - The `DMPLEX` object 9218 . output - If true, statistics will be displayed on `stdout` 9219 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9220 9221 Level: developer 9222 9223 Notes: 9224 This is mainly intended for debugging/testing purposes. 9225 9226 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9227 9228 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9229 @*/ 9230 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9231 { 9232 DM dmCoarse; 9233 cell_stats_t stats, globalStats; 9234 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9235 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9236 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9237 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9238 PetscMPIInt rank, size; 9239 9240 PetscFunctionBegin; 9241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9242 stats.min = PETSC_MAX_REAL; 9243 stats.max = PETSC_MIN_REAL; 9244 stats.sum = stats.squaresum = 0.; 9245 stats.count = 0; 9246 9247 PetscCallMPI(MPI_Comm_size(comm, &size)); 9248 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9249 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9250 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9251 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9252 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9253 for (c = cStart; c < cEnd; c++) { 9254 PetscInt i; 9255 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9256 9257 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9258 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9259 for (i = 0; i < PetscSqr(cdim); ++i) { 9260 frobJ += J[i] * J[i]; 9261 frobInvJ += invJ[i] * invJ[i]; 9262 } 9263 cond2 = frobJ * frobInvJ; 9264 cond = PetscSqrtReal(cond2); 9265 9266 stats.min = PetscMin(stats.min, cond); 9267 stats.max = PetscMax(stats.max, cond); 9268 stats.sum += cond; 9269 stats.squaresum += cond2; 9270 stats.count++; 9271 if (output && cond > limit) { 9272 PetscSection coordSection; 9273 Vec coordsLocal; 9274 PetscScalar *coords = NULL; 9275 PetscInt Nv, d, clSize, cl, *closure = NULL; 9276 9277 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9278 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9279 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9280 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9281 for (i = 0; i < Nv / cdim; ++i) { 9282 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9283 for (d = 0; d < cdim; ++d) { 9284 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9285 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9286 } 9287 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9288 } 9289 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9290 for (cl = 0; cl < clSize * 2; cl += 2) { 9291 const PetscInt edge = closure[cl]; 9292 9293 if ((edge >= eStart) && (edge < eEnd)) { 9294 PetscReal len; 9295 9296 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9297 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9298 } 9299 } 9300 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9301 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9302 } 9303 } 9304 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9305 9306 if (size > 1) { 9307 PetscMPIInt blockLengths[2] = {4, 1}; 9308 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9309 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9310 MPI_Op statReduce; 9311 9312 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9313 PetscCallMPI(MPI_Type_commit(&statType)); 9314 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9315 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9316 PetscCallMPI(MPI_Op_free(&statReduce)); 9317 PetscCallMPI(MPI_Type_free(&statType)); 9318 } else { 9319 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9320 } 9321 if (rank == 0) { 9322 count = globalStats.count; 9323 min = globalStats.min; 9324 max = globalStats.max; 9325 mean = globalStats.sum / globalStats.count; 9326 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9327 } 9328 9329 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)); 9330 PetscCall(PetscFree2(J, invJ)); 9331 9332 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9333 if (dmCoarse) { 9334 PetscBool isplex; 9335 9336 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9337 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9338 } 9339 PetscFunctionReturn(PETSC_SUCCESS); 9340 } 9341 9342 /*@ 9343 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9344 orthogonal quality below given tolerance. 9345 9346 Collective 9347 9348 Input Parameters: 9349 + dm - The `DMPLEX` object 9350 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9351 - atol - [0, 1] Absolute tolerance for tagging cells. 9352 9353 Output Parameters: 9354 + OrthQual - `Vec` containing orthogonal quality per cell 9355 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9356 9357 Options Database Keys: 9358 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9359 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9360 9361 Level: intermediate 9362 9363 Notes: 9364 Orthogonal quality is given by the following formula\: 9365 9366 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9367 9368 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 9369 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9370 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9371 calculating the cosine of the angle between these vectors. 9372 9373 Orthogonal quality ranges from 1 (best) to 0 (worst). 9374 9375 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9376 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9377 9378 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9379 9380 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9381 @*/ 9382 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9383 { 9384 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9385 PetscInt *idx; 9386 PetscScalar *oqVals; 9387 const PetscScalar *cellGeomArr, *faceGeomArr; 9388 PetscReal *ci, *fi, *Ai; 9389 MPI_Comm comm; 9390 Vec cellgeom, facegeom; 9391 DM dmFace, dmCell; 9392 IS glob; 9393 ISLocalToGlobalMapping ltog; 9394 PetscViewer vwr; 9395 9396 PetscFunctionBegin; 9397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9398 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9399 PetscAssertPointer(OrthQual, 4); 9400 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9401 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9402 PetscCall(DMGetDimension(dm, &nc)); 9403 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9404 { 9405 DMPlexInterpolatedFlag interpFlag; 9406 9407 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9408 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9409 PetscMPIInt rank; 9410 9411 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9412 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9413 } 9414 } 9415 if (OrthQualLabel) { 9416 PetscAssertPointer(OrthQualLabel, 5); 9417 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9418 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9419 } else { 9420 *OrthQualLabel = NULL; 9421 } 9422 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9423 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9424 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9425 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9426 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9427 PetscCall(VecCreate(comm, OrthQual)); 9428 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9429 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9430 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9431 PetscCall(VecSetUp(*OrthQual)); 9432 PetscCall(ISDestroy(&glob)); 9433 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9434 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9435 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9436 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9437 PetscCall(VecGetDM(cellgeom, &dmCell)); 9438 PetscCall(VecGetDM(facegeom, &dmFace)); 9439 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9440 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9441 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9442 PetscInt cellarr[2], *adj = NULL; 9443 PetscScalar *cArr, *fArr; 9444 PetscReal minvalc = 1.0, minvalf = 1.0; 9445 PetscFVCellGeom *cg; 9446 9447 idx[cellIter] = cell - cStart; 9448 cellarr[0] = cell; 9449 /* Make indexing into cellGeom easier */ 9450 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9451 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9452 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9453 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9454 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9455 PetscInt i; 9456 const PetscInt neigh = adj[cellneigh]; 9457 PetscReal normci = 0, normfi = 0, normai = 0; 9458 PetscFVCellGeom *cgneigh; 9459 PetscFVFaceGeom *fg; 9460 9461 /* Don't count ourselves in the neighbor list */ 9462 if (neigh == cell) continue; 9463 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9464 cellarr[1] = neigh; 9465 { 9466 PetscInt numcovpts; 9467 const PetscInt *covpts; 9468 9469 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9470 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9471 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9472 } 9473 9474 /* Compute c_i, f_i and their norms */ 9475 for (i = 0; i < nc; i++) { 9476 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9477 fi[i] = fg->centroid[i] - cg->centroid[i]; 9478 Ai[i] = fg->normal[i]; 9479 normci += PetscPowReal(ci[i], 2); 9480 normfi += PetscPowReal(fi[i], 2); 9481 normai += PetscPowReal(Ai[i], 2); 9482 } 9483 normci = PetscSqrtReal(normci); 9484 normfi = PetscSqrtReal(normfi); 9485 normai = PetscSqrtReal(normai); 9486 9487 /* Normalize and compute for each face-cell-normal pair */ 9488 for (i = 0; i < nc; i++) { 9489 ci[i] = ci[i] / normci; 9490 fi[i] = fi[i] / normfi; 9491 Ai[i] = Ai[i] / normai; 9492 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9493 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9494 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9495 } 9496 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9497 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9498 } 9499 PetscCall(PetscFree(adj)); 9500 PetscCall(PetscFree2(cArr, fArr)); 9501 /* Defer to cell if they're equal */ 9502 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9503 if (OrthQualLabel) { 9504 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9505 } 9506 } 9507 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9508 PetscCall(VecAssemblyBegin(*OrthQual)); 9509 PetscCall(VecAssemblyEnd(*OrthQual)); 9510 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9511 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9512 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9513 if (OrthQualLabel) { 9514 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9515 } 9516 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9517 PetscCall(PetscViewerDestroy(&vwr)); 9518 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9519 PetscFunctionReturn(PETSC_SUCCESS); 9520 } 9521 9522 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9523 * interpolator construction */ 9524 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9525 { 9526 PetscSection section, newSection, gsection; 9527 PetscSF sf; 9528 PetscBool hasConstraints, ghasConstraints; 9529 9530 PetscFunctionBegin; 9531 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9532 PetscAssertPointer(odm, 2); 9533 PetscCall(DMGetLocalSection(dm, §ion)); 9534 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9535 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9536 if (!ghasConstraints) { 9537 PetscCall(PetscObjectReference((PetscObject)dm)); 9538 *odm = dm; 9539 PetscFunctionReturn(PETSC_SUCCESS); 9540 } 9541 PetscCall(DMClone(dm, odm)); 9542 PetscCall(DMCopyFields(dm, *odm)); 9543 PetscCall(DMGetLocalSection(*odm, &newSection)); 9544 PetscCall(DMGetPointSF(*odm, &sf)); 9545 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9546 PetscCall(DMSetGlobalSection(*odm, gsection)); 9547 PetscCall(PetscSectionDestroy(&gsection)); 9548 PetscFunctionReturn(PETSC_SUCCESS); 9549 } 9550 9551 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9552 { 9553 DM dmco, dmfo; 9554 Mat interpo; 9555 Vec rscale; 9556 Vec cglobalo, clocal; 9557 Vec fglobal, fglobalo, flocal; 9558 PetscBool regular; 9559 9560 PetscFunctionBegin; 9561 PetscCall(DMGetFullDM(dmc, &dmco)); 9562 PetscCall(DMGetFullDM(dmf, &dmfo)); 9563 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9564 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9565 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9566 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9567 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9568 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9569 PetscCall(VecSet(cglobalo, 0.)); 9570 PetscCall(VecSet(clocal, 0.)); 9571 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9572 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9573 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9574 PetscCall(VecSet(fglobal, 0.)); 9575 PetscCall(VecSet(fglobalo, 0.)); 9576 PetscCall(VecSet(flocal, 0.)); 9577 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9578 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9579 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9580 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9581 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9582 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9583 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9584 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9585 *shift = fglobal; 9586 PetscCall(VecDestroy(&flocal)); 9587 PetscCall(VecDestroy(&fglobalo)); 9588 PetscCall(VecDestroy(&clocal)); 9589 PetscCall(VecDestroy(&cglobalo)); 9590 PetscCall(VecDestroy(&rscale)); 9591 PetscCall(MatDestroy(&interpo)); 9592 PetscCall(DMDestroy(&dmfo)); 9593 PetscCall(DMDestroy(&dmco)); 9594 PetscFunctionReturn(PETSC_SUCCESS); 9595 } 9596 9597 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9598 { 9599 PetscObject shifto; 9600 Vec shift; 9601 9602 PetscFunctionBegin; 9603 if (!interp) { 9604 Vec rscale; 9605 9606 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9607 PetscCall(VecDestroy(&rscale)); 9608 } else { 9609 PetscCall(PetscObjectReference((PetscObject)interp)); 9610 } 9611 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9612 if (!shifto) { 9613 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9614 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9615 shifto = (PetscObject)shift; 9616 PetscCall(VecDestroy(&shift)); 9617 } 9618 shift = (Vec)shifto; 9619 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9620 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9621 PetscCall(MatDestroy(&interp)); 9622 PetscFunctionReturn(PETSC_SUCCESS); 9623 } 9624 9625 /* Pointwise interpolation 9626 Just code FEM for now 9627 u^f = I u^c 9628 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9629 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9630 I_{ij} = psi^f_i phi^c_j 9631 */ 9632 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9633 { 9634 PetscSection gsc, gsf; 9635 PetscInt m, n; 9636 void *ctx; 9637 DM cdm; 9638 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9639 9640 PetscFunctionBegin; 9641 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9642 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9643 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9644 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9645 9646 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9647 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9648 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9649 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9650 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9651 9652 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9653 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9654 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9655 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9656 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9657 if (scaling) { 9658 /* Use naive scaling */ 9659 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9660 } 9661 PetscFunctionReturn(PETSC_SUCCESS); 9662 } 9663 9664 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9665 { 9666 VecScatter ctx; 9667 9668 PetscFunctionBegin; 9669 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9670 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9671 PetscCall(VecScatterDestroy(&ctx)); 9672 PetscFunctionReturn(PETSC_SUCCESS); 9673 } 9674 9675 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[]) 9676 { 9677 const PetscInt Nc = uOff[1] - uOff[0]; 9678 PetscInt c; 9679 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9680 } 9681 9682 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9683 { 9684 DM dmc; 9685 PetscDS ds; 9686 Vec ones, locmass; 9687 IS cellIS; 9688 PetscFormKey key; 9689 PetscInt depth; 9690 9691 PetscFunctionBegin; 9692 PetscCall(DMClone(dm, &dmc)); 9693 PetscCall(DMCopyDisc(dm, dmc)); 9694 PetscCall(DMGetDS(dmc, &ds)); 9695 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9696 PetscCall(DMCreateGlobalVector(dmc, mass)); 9697 PetscCall(DMGetLocalVector(dmc, &ones)); 9698 PetscCall(DMGetLocalVector(dmc, &locmass)); 9699 PetscCall(DMPlexGetDepth(dmc, &depth)); 9700 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9701 PetscCall(VecSet(locmass, 0.0)); 9702 PetscCall(VecSet(ones, 1.0)); 9703 key.label = NULL; 9704 key.value = 0; 9705 key.field = 0; 9706 key.part = 0; 9707 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9708 PetscCall(ISDestroy(&cellIS)); 9709 PetscCall(VecSet(*mass, 0.0)); 9710 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9711 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9712 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9713 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9714 PetscCall(DMDestroy(&dmc)); 9715 PetscFunctionReturn(PETSC_SUCCESS); 9716 } 9717 9718 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9719 { 9720 PetscSection gsc, gsf; 9721 PetscInt m, n; 9722 void *ctx; 9723 DM cdm; 9724 PetscBool regular; 9725 9726 PetscFunctionBegin; 9727 if (dmFine == dmCoarse) { 9728 DM dmc; 9729 PetscDS ds; 9730 PetscWeakForm wf; 9731 Vec u; 9732 IS cellIS; 9733 PetscFormKey key; 9734 PetscInt depth; 9735 9736 PetscCall(DMClone(dmFine, &dmc)); 9737 PetscCall(DMCopyDisc(dmFine, dmc)); 9738 PetscCall(DMGetDS(dmc, &ds)); 9739 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9740 PetscCall(PetscWeakFormClear(wf)); 9741 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9742 PetscCall(DMCreateMatrix(dmc, mass)); 9743 PetscCall(DMGetLocalVector(dmc, &u)); 9744 PetscCall(DMPlexGetDepth(dmc, &depth)); 9745 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9746 PetscCall(MatZeroEntries(*mass)); 9747 key.label = NULL; 9748 key.value = 0; 9749 key.field = 0; 9750 key.part = 0; 9751 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9752 PetscCall(ISDestroy(&cellIS)); 9753 PetscCall(DMRestoreLocalVector(dmc, &u)); 9754 PetscCall(DMDestroy(&dmc)); 9755 } else { 9756 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9757 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9758 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9759 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9760 9761 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9762 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9763 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9764 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9765 9766 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9767 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9768 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9769 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9770 } 9771 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9772 PetscFunctionReturn(PETSC_SUCCESS); 9773 } 9774 9775 /*@ 9776 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9777 9778 Input Parameter: 9779 . dm - The `DMPLEX` object 9780 9781 Output Parameter: 9782 . regular - The flag 9783 9784 Level: intermediate 9785 9786 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9787 @*/ 9788 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9789 { 9790 PetscFunctionBegin; 9791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9792 PetscAssertPointer(regular, 2); 9793 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9794 PetscFunctionReturn(PETSC_SUCCESS); 9795 } 9796 9797 /*@ 9798 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9799 9800 Input Parameters: 9801 + dm - The `DMPLEX` object 9802 - regular - The flag 9803 9804 Level: intermediate 9805 9806 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9807 @*/ 9808 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9809 { 9810 PetscFunctionBegin; 9811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9812 ((DM_Plex *)dm->data)->regularRefinement = regular; 9813 PetscFunctionReturn(PETSC_SUCCESS); 9814 } 9815 9816 /*@ 9817 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9818 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9819 9820 Not Collective 9821 9822 Input Parameter: 9823 . dm - The `DMPLEX` object 9824 9825 Output Parameters: 9826 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9827 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9828 9829 Level: intermediate 9830 9831 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9832 @*/ 9833 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9834 { 9835 DM_Plex *plex = (DM_Plex *)dm->data; 9836 9837 PetscFunctionBegin; 9838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9839 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9840 if (anchorSection) *anchorSection = plex->anchorSection; 9841 if (anchorIS) *anchorIS = plex->anchorIS; 9842 PetscFunctionReturn(PETSC_SUCCESS); 9843 } 9844 9845 /*@ 9846 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 9847 9848 Collective 9849 9850 Input Parameters: 9851 + dm - The `DMPLEX` object 9852 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9853 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9854 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9855 9856 Level: intermediate 9857 9858 Notes: 9859 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 9860 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 9861 combination of other points' degrees of freedom. 9862 9863 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9864 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9865 9866 The reference counts of `anchorSection` and `anchorIS` are incremented. 9867 9868 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9869 @*/ 9870 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9871 { 9872 DM_Plex *plex = (DM_Plex *)dm->data; 9873 PetscMPIInt result; 9874 9875 PetscFunctionBegin; 9876 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9877 if (anchorSection) { 9878 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9879 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9880 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9881 } 9882 if (anchorIS) { 9883 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9884 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9885 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9886 } 9887 9888 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9889 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9890 plex->anchorSection = anchorSection; 9891 9892 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9893 PetscCall(ISDestroy(&plex->anchorIS)); 9894 plex->anchorIS = anchorIS; 9895 9896 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9897 PetscInt size, a, pStart, pEnd; 9898 const PetscInt *anchors; 9899 9900 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9901 PetscCall(ISGetLocalSize(anchorIS, &size)); 9902 PetscCall(ISGetIndices(anchorIS, &anchors)); 9903 for (a = 0; a < size; a++) { 9904 PetscInt p; 9905 9906 p = anchors[a]; 9907 if (p >= pStart && p < pEnd) { 9908 PetscInt dof; 9909 9910 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9911 if (dof) { 9912 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9913 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9914 } 9915 } 9916 } 9917 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9918 } 9919 /* reset the generic constraints */ 9920 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9921 PetscFunctionReturn(PETSC_SUCCESS); 9922 } 9923 9924 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9925 { 9926 PetscSection anchorSection; 9927 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9928 9929 PetscFunctionBegin; 9930 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9931 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9932 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9933 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9934 if (numFields) { 9935 PetscInt f; 9936 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9937 9938 for (f = 0; f < numFields; f++) { 9939 PetscInt numComp; 9940 9941 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9942 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9943 } 9944 } 9945 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9946 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9947 pStart = PetscMax(pStart, sStart); 9948 pEnd = PetscMin(pEnd, sEnd); 9949 pEnd = PetscMax(pStart, pEnd); 9950 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9951 for (p = pStart; p < pEnd; p++) { 9952 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9953 if (dof) { 9954 PetscCall(PetscSectionGetDof(section, p, &dof)); 9955 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9956 for (f = 0; f < numFields; f++) { 9957 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9958 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9959 } 9960 } 9961 } 9962 PetscCall(PetscSectionSetUp(*cSec)); 9963 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9964 PetscFunctionReturn(PETSC_SUCCESS); 9965 } 9966 9967 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9968 { 9969 PetscSection aSec; 9970 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9971 const PetscInt *anchors; 9972 PetscInt numFields, f; 9973 IS aIS; 9974 MatType mtype; 9975 PetscBool iscuda, iskokkos; 9976 9977 PetscFunctionBegin; 9978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9979 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9980 PetscCall(PetscSectionGetStorageSize(section, &n)); 9981 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9982 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9983 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9984 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9985 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9986 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9987 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9988 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9989 else mtype = MATSEQAIJ; 9990 PetscCall(MatSetType(*cMat, mtype)); 9991 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9992 PetscCall(ISGetIndices(aIS, &anchors)); 9993 /* cSec will be a subset of aSec and section */ 9994 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9995 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9996 PetscCall(PetscMalloc1(m + 1, &i)); 9997 i[0] = 0; 9998 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9999 for (p = pStart; p < pEnd; p++) { 10000 PetscInt rDof, rOff, r; 10001 10002 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10003 if (!rDof) continue; 10004 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10005 if (numFields) { 10006 for (f = 0; f < numFields; f++) { 10007 annz = 0; 10008 for (r = 0; r < rDof; r++) { 10009 a = anchors[rOff + r]; 10010 if (a < sStart || a >= sEnd) continue; 10011 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10012 annz += aDof; 10013 } 10014 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10015 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10016 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10017 } 10018 } else { 10019 annz = 0; 10020 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10021 for (q = 0; q < dof; q++) { 10022 a = anchors[rOff + q]; 10023 if (a < sStart || a >= sEnd) continue; 10024 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10025 annz += aDof; 10026 } 10027 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10028 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10029 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10030 } 10031 } 10032 nnz = i[m]; 10033 PetscCall(PetscMalloc1(nnz, &j)); 10034 offset = 0; 10035 for (p = pStart; p < pEnd; p++) { 10036 if (numFields) { 10037 for (f = 0; f < numFields; f++) { 10038 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10039 for (q = 0; q < dof; q++) { 10040 PetscInt rDof, rOff, r; 10041 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10042 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10043 for (r = 0; r < rDof; r++) { 10044 PetscInt s; 10045 10046 a = anchors[rOff + r]; 10047 if (a < sStart || a >= sEnd) continue; 10048 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10049 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10050 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10051 } 10052 } 10053 } 10054 } else { 10055 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10056 for (q = 0; q < dof; q++) { 10057 PetscInt rDof, rOff, r; 10058 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10059 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10060 for (r = 0; r < rDof; r++) { 10061 PetscInt s; 10062 10063 a = anchors[rOff + r]; 10064 if (a < sStart || a >= sEnd) continue; 10065 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10066 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10067 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10068 } 10069 } 10070 } 10071 } 10072 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10073 PetscCall(PetscFree(i)); 10074 PetscCall(PetscFree(j)); 10075 PetscCall(ISRestoreIndices(aIS, &anchors)); 10076 PetscFunctionReturn(PETSC_SUCCESS); 10077 } 10078 10079 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10080 { 10081 DM_Plex *plex = (DM_Plex *)dm->data; 10082 PetscSection anchorSection, section, cSec; 10083 Mat cMat; 10084 10085 PetscFunctionBegin; 10086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10087 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10088 if (anchorSection) { 10089 PetscInt Nf; 10090 10091 PetscCall(DMGetLocalSection(dm, §ion)); 10092 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10093 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10094 PetscCall(DMGetNumFields(dm, &Nf)); 10095 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10096 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10097 PetscCall(PetscSectionDestroy(&cSec)); 10098 PetscCall(MatDestroy(&cMat)); 10099 } 10100 PetscFunctionReturn(PETSC_SUCCESS); 10101 } 10102 10103 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10104 { 10105 IS subis; 10106 PetscSection section, subsection; 10107 10108 PetscFunctionBegin; 10109 PetscCall(DMGetLocalSection(dm, §ion)); 10110 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10111 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10112 /* Create subdomain */ 10113 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10114 /* Create submodel */ 10115 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10116 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10117 PetscCall(DMSetLocalSection(*subdm, subsection)); 10118 PetscCall(PetscSectionDestroy(&subsection)); 10119 PetscCall(DMCopyDisc(dm, *subdm)); 10120 /* Create map from submodel to global model */ 10121 if (is) { 10122 PetscSection sectionGlobal, subsectionGlobal; 10123 IS spIS; 10124 const PetscInt *spmap; 10125 PetscInt *subIndices; 10126 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10127 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10128 10129 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10130 PetscCall(ISGetIndices(spIS, &spmap)); 10131 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10132 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10133 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10134 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10135 for (p = pStart; p < pEnd; ++p) { 10136 PetscInt gdof, pSubSize = 0; 10137 10138 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10139 if (gdof > 0) { 10140 for (f = 0; f < Nf; ++f) { 10141 PetscInt fdof, fcdof; 10142 10143 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10144 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10145 pSubSize += fdof - fcdof; 10146 } 10147 subSize += pSubSize; 10148 if (pSubSize) { 10149 if (bs < 0) { 10150 bs = pSubSize; 10151 } else if (bs != pSubSize) { 10152 /* Layout does not admit a pointwise block size */ 10153 bs = 1; 10154 } 10155 } 10156 } 10157 } 10158 /* Must have same blocksize on all procs (some might have no points) */ 10159 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10160 bsLocal[1] = bs; 10161 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10162 if (bsMinMax[0] != bsMinMax[1]) { 10163 bs = 1; 10164 } else { 10165 bs = bsMinMax[0]; 10166 } 10167 PetscCall(PetscMalloc1(subSize, &subIndices)); 10168 for (p = pStart; p < pEnd; ++p) { 10169 PetscInt gdof, goff; 10170 10171 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10172 if (gdof > 0) { 10173 const PetscInt point = spmap[p]; 10174 10175 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10176 for (f = 0; f < Nf; ++f) { 10177 PetscInt fdof, fcdof, fc, f2, poff = 0; 10178 10179 /* Can get rid of this loop by storing field information in the global section */ 10180 for (f2 = 0; f2 < f; ++f2) { 10181 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10182 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10183 poff += fdof - fcdof; 10184 } 10185 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10186 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10187 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10188 } 10189 } 10190 } 10191 PetscCall(ISRestoreIndices(spIS, &spmap)); 10192 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10193 if (bs > 1) { 10194 /* We need to check that the block size does not come from non-contiguous fields */ 10195 PetscInt i, j, set = 1; 10196 for (i = 0; i < subSize; i += bs) { 10197 for (j = 0; j < bs; ++j) { 10198 if (subIndices[i + j] != subIndices[i] + j) { 10199 set = 0; 10200 break; 10201 } 10202 } 10203 } 10204 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10205 } 10206 /* Attach nullspace */ 10207 for (f = 0; f < Nf; ++f) { 10208 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10209 if ((*subdm)->nullspaceConstructors[f]) break; 10210 } 10211 if (f < Nf) { 10212 MatNullSpace nullSpace; 10213 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10214 10215 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10216 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10217 } 10218 } 10219 PetscFunctionReturn(PETSC_SUCCESS); 10220 } 10221 10222 /*@ 10223 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10224 10225 Input Parameters: 10226 + dm - The `DM` 10227 - dummy - unused argument 10228 10229 Options Database Key: 10230 . -dm_plex_monitor_throughput - Activate the monitor 10231 10232 Level: developer 10233 10234 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10235 @*/ 10236 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10237 { 10238 PetscLogHandler default_handler; 10239 10240 PetscFunctionBegin; 10241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10242 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10243 if (default_handler) { 10244 PetscLogEvent event; 10245 PetscEventPerfInfo eventInfo; 10246 PetscReal cellRate, flopRate; 10247 PetscInt cStart, cEnd, Nf, N; 10248 const char *name; 10249 10250 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10251 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10252 PetscCall(DMGetNumFields(dm, &Nf)); 10253 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10254 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10255 N = (cEnd - cStart) * Nf * eventInfo.count; 10256 flopRate = eventInfo.flops / eventInfo.time; 10257 cellRate = N / eventInfo.time; 10258 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))); 10259 } else { 10260 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."); 10261 } 10262 PetscFunctionReturn(PETSC_SUCCESS); 10263 } 10264