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 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 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; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscBool found = PETSC_FALSE; 89 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 90 91 PetscFunctionBegin; 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 94 PetscCall(ISGetLocalSize(valueIS, &Nct)); 95 PetscCall(ISGetIndices(valueIS, &ctypes)); 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 found = PETSC_TRUE; 114 } 115 if (!Nct || !found) cS = cE = 0; 116 PetscCall(ISDestroy(&valueIS)); 117 // Reset label for fast lookup 118 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 119 if (cStart) *cStart = cS; 120 if (cEnd) *cEnd = cE; 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 125 { 126 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 127 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 128 129 PetscFunctionBegin; 130 *ft = PETSC_VTK_INVALID; 131 PetscCall(DMGetCoordinateDim(dm, &cdim)); 132 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 133 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 134 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 135 if (field >= 0) { 136 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 137 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 140 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 141 } 142 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 143 if (globalvcdof[0]) { 144 *sStart = vStart; 145 *sEnd = vEnd; 146 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 147 else *ft = PETSC_VTK_POINT_FIELD; 148 } else if (globalvcdof[1]) { 149 *sStart = cStart; 150 *sEnd = cEnd; 151 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 152 else *ft = PETSC_VTK_CELL_FIELD; 153 } else { 154 if (field >= 0) { 155 const char *fieldname; 156 157 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 158 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 159 } else { 160 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 161 } 162 } 163 PetscFunctionReturn(PETSC_SUCCESS); 164 } 165 166 /*@ 167 DMPlexVecView1D - Plot many 1D solutions on the same line graph 168 169 Collective 170 171 Input Parameters: 172 + dm - The `DMPLEX` object 173 . n - The number of vectors 174 . u - The array of local vectors 175 - viewer - The `PetscViewer` 176 177 Level: advanced 178 179 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 180 @*/ 181 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 182 { 183 PetscDS ds; 184 PetscDraw draw = NULL; 185 PetscDrawLG lg; 186 Vec coordinates; 187 const PetscScalar *coords, **sol; 188 PetscReal *vals; 189 PetscInt *Nc; 190 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 191 char **names; 192 193 PetscFunctionBegin; 194 PetscCall(DMGetDS(dm, &ds)); 195 PetscCall(PetscDSGetNumFields(ds, &Nf)); 196 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 197 PetscCall(PetscDSGetComponents(ds, &Nc)); 198 199 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 200 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 201 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 202 203 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 204 for (i = 0, l = 0; i < n; ++i) { 205 const char *vname; 206 207 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 208 for (f = 0; f < Nf; ++f) { 209 PetscObject disc; 210 const char *fname; 211 char tmpname[PETSC_MAX_PATH_LEN]; 212 213 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 214 /* TODO Create names for components */ 215 for (c = 0; c < Nc[f]; ++c, ++l) { 216 PetscCall(PetscObjectGetName(disc, &fname)); 217 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 218 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 219 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 220 PetscCall(PetscStrallocpy(tmpname, &names[l])); 221 } 222 } 223 } 224 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 225 /* Just add P_1 support for now */ 226 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 227 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 228 PetscCall(VecGetArrayRead(coordinates, &coords)); 229 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 230 for (v = vStart; v < vEnd; ++v) { 231 PetscScalar *x, *svals; 232 233 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 234 for (i = 0; i < n; ++i) { 235 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 236 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 237 } 238 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 239 } 240 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 241 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 242 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 243 PetscCall(PetscFree3(sol, names, vals)); 244 245 PetscCall(PetscDrawLGDraw(lg)); 246 PetscCall(PetscDrawLGDestroy(&lg)); 247 PetscFunctionReturn(PETSC_SUCCESS); 248 } 249 250 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 251 { 252 DM dm; 253 254 PetscFunctionBegin; 255 PetscCall(VecGetDM(u, &dm)); 256 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 257 PetscFunctionReturn(PETSC_SUCCESS); 258 } 259 260 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 261 { 262 DM dm; 263 PetscSection s; 264 PetscDraw draw, popup; 265 DM cdm; 266 PetscSection coordSection; 267 Vec coordinates; 268 const PetscScalar *array; 269 PetscReal lbound[3], ubound[3]; 270 PetscReal vbound[2], time; 271 PetscBool flg; 272 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 273 const char *name; 274 char title[PETSC_MAX_PATH_LEN]; 275 276 PetscFunctionBegin; 277 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 278 PetscCall(VecGetDM(v, &dm)); 279 PetscCall(DMGetCoordinateDim(dm, &dim)); 280 PetscCall(DMGetLocalSection(dm, &s)); 281 PetscCall(PetscSectionGetNumFields(s, &Nf)); 282 PetscCall(DMGetCoarsenLevel(dm, &level)); 283 PetscCall(DMGetCoordinateDM(dm, &cdm)); 284 PetscCall(DMGetLocalSection(cdm, &coordSection)); 285 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 286 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 287 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 288 289 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 290 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 291 292 PetscCall(VecGetLocalSize(coordinates, &N)); 293 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 294 PetscCall(PetscDrawClear(draw)); 295 296 /* Could implement something like DMDASelectFields() */ 297 for (f = 0; f < Nf; ++f) { 298 DM fdm = dm; 299 Vec fv = v; 300 IS fis; 301 char prefix[PETSC_MAX_PATH_LEN]; 302 const char *fname; 303 304 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 305 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 306 307 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 308 else prefix[0] = '\0'; 309 if (Nf > 1) { 310 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 311 PetscCall(VecGetSubVector(v, fis, &fv)); 312 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 313 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 314 } 315 for (comp = 0; comp < Nc; ++comp, ++w) { 316 PetscInt nmax = 2; 317 318 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 319 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 320 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 321 PetscCall(PetscDrawSetTitle(draw, title)); 322 323 /* TODO Get max and min only for this component */ 324 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 325 if (!flg) { 326 PetscCall(VecMin(fv, NULL, &vbound[0])); 327 PetscCall(VecMax(fv, NULL, &vbound[1])); 328 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 329 } 330 331 PetscCall(PetscDrawGetPopup(draw, &popup)); 332 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 333 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 334 PetscCall(VecGetArrayRead(fv, &array)); 335 for (c = cStart; c < cEnd; ++c) { 336 DMPolytopeType ct; 337 PetscScalar *coords = NULL, *a = NULL; 338 const PetscScalar *coords_arr; 339 PetscBool isDG; 340 PetscInt numCoords; 341 int color[4] = {-1, -1, -1, -1}; 342 343 PetscCall(DMPlexGetCellType(dm, c, &ct)); 344 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 345 if (a) { 346 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 347 color[1] = color[2] = color[3] = color[0]; 348 } else { 349 PetscScalar *vals = NULL; 350 PetscInt numVals, va; 351 352 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 353 if (!numVals) { 354 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 355 continue; 356 } 357 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); 358 switch (numVals / Nc) { 359 case 1: /* P1 Clamped Segment Prism */ 360 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 361 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 362 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 363 break; 364 case 3: /* P1 Triangle */ 365 case 4: /* P1 Quadrangle */ 366 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 367 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 368 break; 369 case 6: /* P2 Triangle */ 370 case 8: /* P2 Quadrangle */ 371 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 372 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 373 break; 374 default: 375 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 376 } 377 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 378 } 379 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 380 switch (numCoords) { 381 case 6: 382 case 12: /* Localized triangle */ 383 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])); 384 break; 385 case 8: 386 case 16: /* Localized quadrilateral */ 387 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 388 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 389 } else { 390 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])); 391 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])); 392 } 393 break; 394 default: 395 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 396 } 397 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 398 } 399 PetscCall(VecRestoreArrayRead(fv, &array)); 400 PetscCall(PetscDrawFlush(draw)); 401 PetscCall(PetscDrawPause(draw)); 402 PetscCall(PetscDrawSave(draw)); 403 } 404 if (Nf > 1) { 405 PetscCall(VecRestoreSubVector(v, fis, &fv)); 406 PetscCall(ISDestroy(&fis)); 407 PetscCall(DMDestroy(&fdm)); 408 } 409 } 410 PetscFunctionReturn(PETSC_SUCCESS); 411 } 412 413 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 414 { 415 DM dm; 416 PetscDraw draw; 417 PetscInt dim; 418 PetscBool isnull; 419 420 PetscFunctionBegin; 421 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 422 PetscCall(PetscDrawIsNull(draw, &isnull)); 423 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 424 425 PetscCall(VecGetDM(v, &dm)); 426 PetscCall(DMGetCoordinateDim(dm, &dim)); 427 switch (dim) { 428 case 1: 429 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 430 break; 431 case 2: 432 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 433 break; 434 default: 435 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 436 } 437 PetscFunctionReturn(PETSC_SUCCESS); 438 } 439 440 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 441 { 442 DM dm; 443 Vec locv; 444 const char *name; 445 PetscSection section; 446 PetscInt pStart, pEnd; 447 PetscInt numFields; 448 PetscViewerVTKFieldType ft; 449 450 PetscFunctionBegin; 451 PetscCall(VecGetDM(v, &dm)); 452 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 453 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 454 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 455 PetscCall(VecCopy(v, locv)); 456 PetscCall(DMGetLocalSection(dm, §ion)); 457 PetscCall(PetscSectionGetNumFields(section, &numFields)); 458 if (!numFields) { 459 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 460 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 461 } else { 462 PetscInt f; 463 464 for (f = 0; f < numFields; f++) { 465 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 466 if (ft == PETSC_VTK_INVALID) continue; 467 PetscCall(PetscObjectReference((PetscObject)locv)); 468 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 469 } 470 PetscCall(VecDestroy(&locv)); 471 } 472 PetscFunctionReturn(PETSC_SUCCESS); 473 } 474 475 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 476 { 477 DM dm; 478 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 479 480 PetscFunctionBegin; 481 PetscCall(VecGetDM(v, &dm)); 482 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 483 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 484 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 485 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 486 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 487 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 488 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 489 PetscInt i, numFields; 490 PetscObject fe; 491 PetscBool fem = PETSC_FALSE; 492 Vec locv = v; 493 const char *name; 494 PetscInt step; 495 PetscReal time; 496 497 PetscCall(DMGetNumFields(dm, &numFields)); 498 for (i = 0; i < numFields; i++) { 499 PetscCall(DMGetField(dm, i, NULL, &fe)); 500 if (fe->classid == PETSCFE_CLASSID) { 501 fem = PETSC_TRUE; 502 break; 503 } 504 } 505 if (fem) { 506 PetscObject isZero; 507 508 PetscCall(DMGetLocalVector(dm, &locv)); 509 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 510 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 511 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 512 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 513 PetscCall(VecCopy(v, locv)); 514 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 515 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 516 } 517 if (isvtk) { 518 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 519 } else if (ishdf5) { 520 #if defined(PETSC_HAVE_HDF5) 521 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 522 #else 523 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 524 #endif 525 } else if (isdraw) { 526 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 527 } else if (isglvis) { 528 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 529 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 530 PetscCall(VecView_GLVis(locv, viewer)); 531 } else if (iscgns) { 532 #if defined(PETSC_HAVE_CGNS) 533 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 534 #else 535 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 536 #endif 537 } 538 if (fem) { 539 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 540 PetscCall(DMRestoreLocalVector(dm, &locv)); 541 } 542 } else { 543 PetscBool isseq; 544 545 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 546 if (isseq) PetscCall(VecView_Seq(v, viewer)); 547 else PetscCall(VecView_MPI(v, viewer)); 548 } 549 PetscFunctionReturn(PETSC_SUCCESS); 550 } 551 552 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 553 { 554 DM dm; 555 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 556 557 PetscFunctionBegin; 558 PetscCall(VecGetDM(v, &dm)); 559 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 562 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 563 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 564 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 565 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 566 if (isvtk || isdraw || isglvis || iscgns) { 567 Vec locv; 568 PetscObject isZero; 569 const char *name; 570 571 PetscCall(DMGetLocalVector(dm, &locv)); 572 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 573 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 574 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 575 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 576 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 577 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 578 PetscCall(VecView_Plex_Local(locv, viewer)); 579 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 580 PetscCall(DMRestoreLocalVector(dm, &locv)); 581 /* Call flush for proper logging of VecView timings */ 582 if (isvtk) PetscCall(PetscViewerFlush(viewer)); 583 } else if (ishdf5) { 584 #if defined(PETSC_HAVE_HDF5) 585 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 586 #else 587 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 588 #endif 589 } else if (isexodusii) { 590 #if defined(PETSC_HAVE_EXODUSII) 591 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 592 #else 593 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 594 #endif 595 } else { 596 PetscBool isseq; 597 598 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 599 if (isseq) PetscCall(VecView_Seq(v, viewer)); 600 else PetscCall(VecView_MPI(v, viewer)); 601 } 602 PetscFunctionReturn(PETSC_SUCCESS); 603 } 604 605 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 606 { 607 DM dm; 608 MPI_Comm comm; 609 PetscViewerFormat format; 610 Vec v; 611 PetscBool isvtk, ishdf5; 612 613 PetscFunctionBegin; 614 PetscCall(VecGetDM(originalv, &dm)); 615 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 616 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 617 PetscCall(PetscViewerGetFormat(viewer, &format)); 618 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 619 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 620 if (format == PETSC_VIEWER_NATIVE) { 621 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 622 /* this need a better fix */ 623 if (dm->useNatural) { 624 if (dm->sfNatural) { 625 const char *vecname; 626 PetscInt n, nroots; 627 628 PetscCall(VecGetLocalSize(originalv, &n)); 629 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 630 if (n == nroots) { 631 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 632 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 633 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 634 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 635 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 636 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 637 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 638 } else v = originalv; 639 } else v = originalv; 640 641 if (ishdf5) { 642 #if defined(PETSC_HAVE_HDF5) 643 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 644 #else 645 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 646 #endif 647 } else if (isvtk) { 648 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 649 } else { 650 PetscBool isseq; 651 652 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 653 if (isseq) PetscCall(VecView_Seq(v, viewer)); 654 else PetscCall(VecView_MPI(v, viewer)); 655 } 656 if (v != originalv) PetscCall(VecDestroy(&v)); 657 PetscFunctionReturn(PETSC_SUCCESS); 658 } 659 660 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 661 { 662 DM dm; 663 PetscBool ishdf5; 664 665 PetscFunctionBegin; 666 PetscCall(VecGetDM(v, &dm)); 667 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 668 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 669 if (ishdf5) { 670 DM dmBC; 671 Vec gv; 672 const char *name; 673 674 PetscCall(DMGetOutputDM(dm, &dmBC)); 675 PetscCall(DMGetGlobalVector(dmBC, &gv)); 676 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 677 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 678 PetscCall(VecLoad_Default(gv, viewer)); 679 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 680 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 681 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 682 } else PetscCall(VecLoad_Default(v, viewer)); 683 PetscFunctionReturn(PETSC_SUCCESS); 684 } 685 686 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 687 { 688 DM dm; 689 PetscBool ishdf5, isexodusii; 690 691 PetscFunctionBegin; 692 PetscCall(VecGetDM(v, &dm)); 693 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 694 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 695 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 696 if (ishdf5) { 697 #if defined(PETSC_HAVE_HDF5) 698 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 699 #else 700 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 701 #endif 702 } else if (isexodusii) { 703 #if defined(PETSC_HAVE_EXODUSII) 704 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 705 #else 706 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 707 #endif 708 } else PetscCall(VecLoad_Default(v, viewer)); 709 PetscFunctionReturn(PETSC_SUCCESS); 710 } 711 712 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 713 { 714 DM dm; 715 PetscViewerFormat format; 716 PetscBool ishdf5; 717 718 PetscFunctionBegin; 719 PetscCall(VecGetDM(originalv, &dm)); 720 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 721 PetscCall(PetscViewerGetFormat(viewer, &format)); 722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 723 if (format == PETSC_VIEWER_NATIVE) { 724 if (dm->useNatural) { 725 if (dm->sfNatural) { 726 if (ishdf5) { 727 #if defined(PETSC_HAVE_HDF5) 728 Vec v; 729 const char *vecname; 730 731 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 732 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 733 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 734 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 735 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 736 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 737 PetscCall(VecDestroy(&v)); 738 #else 739 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 740 #endif 741 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 742 } 743 } else PetscCall(VecLoad_Default(originalv, viewer)); 744 } 745 PetscFunctionReturn(PETSC_SUCCESS); 746 } 747 748 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 749 { 750 PetscSection coordSection; 751 Vec coordinates; 752 DMLabel depthLabel, celltypeLabel; 753 const char *name[4]; 754 const PetscScalar *a; 755 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 756 757 PetscFunctionBegin; 758 PetscCall(DMGetDimension(dm, &dim)); 759 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 760 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 761 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 762 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 763 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 764 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 765 PetscCall(VecGetArrayRead(coordinates, &a)); 766 name[0] = "vertex"; 767 name[1] = "edge"; 768 name[dim - 1] = "face"; 769 name[dim] = "cell"; 770 for (c = cStart; c < cEnd; ++c) { 771 PetscInt *closure = NULL; 772 PetscInt closureSize, cl, ct; 773 774 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 775 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 776 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 777 PetscCall(PetscViewerASCIIPushTab(viewer)); 778 for (cl = 0; cl < closureSize * 2; cl += 2) { 779 PetscInt point = closure[cl], depth, dof, off, d, p; 780 781 if ((point < pStart) || (point >= pEnd)) continue; 782 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 783 if (!dof) continue; 784 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 785 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 786 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 787 for (p = 0; p < dof / dim; ++p) { 788 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 789 for (d = 0; d < dim; ++d) { 790 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 791 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 792 } 793 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 794 } 795 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 796 } 797 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 798 PetscCall(PetscViewerASCIIPopTab(viewer)); 799 } 800 PetscCall(VecRestoreArrayRead(coordinates, &a)); 801 PetscFunctionReturn(PETSC_SUCCESS); 802 } 803 804 typedef enum { 805 CS_CARTESIAN, 806 CS_POLAR, 807 CS_CYLINDRICAL, 808 CS_SPHERICAL 809 } CoordSystem; 810 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 811 812 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 813 { 814 PetscInt i; 815 816 PetscFunctionBegin; 817 if (dim > 3) { 818 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 819 } else { 820 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 821 822 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 823 switch (cs) { 824 case CS_CARTESIAN: 825 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 826 break; 827 case CS_POLAR: 828 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 829 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 830 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 831 break; 832 case CS_CYLINDRICAL: 833 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 834 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 835 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 836 trcoords[2] = coords[2]; 837 break; 838 case CS_SPHERICAL: 839 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 840 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 841 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 842 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 843 break; 844 } 845 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 846 } 847 PetscFunctionReturn(PETSC_SUCCESS); 848 } 849 850 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 851 { 852 DM_Plex *mesh = (DM_Plex *)dm->data; 853 DM cdm, cdmCell; 854 PetscSection coordSection, coordSectionCell; 855 Vec coordinates, coordinatesCell; 856 PetscViewerFormat format; 857 858 PetscFunctionBegin; 859 PetscCall(PetscViewerGetFormat(viewer, &format)); 860 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 861 const char *name; 862 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 863 PetscInt pStart, pEnd, p, numLabels, l; 864 PetscMPIInt rank, size; 865 866 PetscCall(DMGetCoordinateDM(dm, &cdm)); 867 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 868 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 869 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 870 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 871 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 872 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 873 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 874 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 875 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 876 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 877 PetscCall(DMGetDimension(dm, &dim)); 878 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 879 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 880 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 881 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 882 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 883 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 884 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 885 for (p = pStart; p < pEnd; ++p) { 886 PetscInt dof, off, s; 887 888 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 889 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 890 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 891 } 892 PetscCall(PetscViewerFlush(viewer)); 893 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 894 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 895 for (p = pStart; p < pEnd; ++p) { 896 PetscInt dof, off, c; 897 898 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 899 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 900 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])); 901 } 902 PetscCall(PetscViewerFlush(viewer)); 903 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 904 if (coordSection && coordinates) { 905 CoordSystem cs = CS_CARTESIAN; 906 const PetscScalar *array, *arrayCell = NULL; 907 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 908 PetscMPIInt rank; 909 const char *name; 910 911 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 912 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 913 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 914 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 915 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 916 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 917 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 918 pStart = PetscMin(pvStart, pcStart); 919 pEnd = PetscMax(pvEnd, pcEnd); 920 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 921 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 922 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 923 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 924 925 PetscCall(VecGetArrayRead(coordinates, &array)); 926 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 927 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 928 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 929 for (p = pStart; p < pEnd; ++p) { 930 PetscInt dof, off; 931 932 if (p >= pvStart && p < pvEnd) { 933 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 934 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 935 if (dof) { 936 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 937 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 938 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 939 } 940 } 941 if (cdmCell && p >= pcStart && p < pcEnd) { 942 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 943 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 944 if (dof) { 945 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 946 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 947 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 948 } 949 } 950 } 951 PetscCall(PetscViewerFlush(viewer)); 952 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 953 PetscCall(VecRestoreArrayRead(coordinates, &array)); 954 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 955 } 956 PetscCall(DMGetNumLabels(dm, &numLabels)); 957 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 958 for (l = 0; l < numLabels; ++l) { 959 DMLabel label; 960 PetscBool isdepth; 961 const char *name; 962 963 PetscCall(DMGetLabelName(dm, l, &name)); 964 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 965 if (isdepth) continue; 966 PetscCall(DMGetLabel(dm, name, &label)); 967 PetscCall(DMLabelView(label, viewer)); 968 } 969 if (size > 1) { 970 PetscSF sf; 971 972 PetscCall(DMGetPointSF(dm, &sf)); 973 PetscCall(PetscSFView(sf, viewer)); 974 } 975 if (mesh->periodic.face_sfs) 976 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 977 PetscCall(PetscViewerFlush(viewer)); 978 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 979 const char *name, *color; 980 const char *defcolors[3] = {"gray", "orange", "green"}; 981 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 982 char lname[PETSC_MAX_PATH_LEN]; 983 PetscReal scale = 2.0; 984 PetscReal tikzscale = 1.0; 985 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 986 double tcoords[3]; 987 PetscScalar *coords; 988 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 989 PetscMPIInt rank, size; 990 char **names, **colors, **lcolors; 991 PetscBool flg, lflg; 992 PetscBT wp = NULL; 993 PetscInt pEnd, pStart; 994 995 PetscCall(DMGetCoordinateDM(dm, &cdm)); 996 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 997 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 998 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 999 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1000 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1001 PetscCall(DMGetDimension(dm, &dim)); 1002 PetscCall(DMPlexGetDepth(dm, &depth)); 1003 PetscCall(DMGetNumLabels(dm, &numLabels)); 1004 numLabels = PetscMax(numLabels, 10); 1005 numColors = 10; 1006 numLColors = 10; 1007 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1008 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1009 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1010 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1011 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1012 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1013 n = 4; 1014 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1015 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1016 n = 4; 1017 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1018 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1019 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1020 if (!useLabels) numLabels = 0; 1021 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1022 if (!useColors) { 1023 numColors = 3; 1024 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1025 } 1026 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1027 if (!useColors) { 1028 numLColors = 4; 1029 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1030 } 1031 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1032 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1033 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1034 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1035 if (depth < dim) plotEdges = PETSC_FALSE; 1036 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1037 1038 /* filter points with labelvalue != labeldefaultvalue */ 1039 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1040 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1041 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1042 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1043 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1044 if (lflg) { 1045 DMLabel lbl; 1046 1047 PetscCall(DMGetLabel(dm, lname, &lbl)); 1048 if (lbl) { 1049 PetscInt val, defval; 1050 1051 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1052 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1053 for (c = pStart; c < pEnd; c++) { 1054 PetscInt *closure = NULL; 1055 PetscInt closureSize; 1056 1057 PetscCall(DMLabelGetValue(lbl, c, &val)); 1058 if (val == defval) continue; 1059 1060 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1061 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1062 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1063 } 1064 } 1065 } 1066 1067 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1068 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1069 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1070 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1071 \\documentclass[tikz]{standalone}\n\n\ 1072 \\usepackage{pgflibraryshapes}\n\ 1073 \\usetikzlibrary{backgrounds}\n\ 1074 \\usetikzlibrary{arrows}\n\ 1075 \\begin{document}\n")); 1076 if (size > 1) { 1077 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1078 for (p = 0; p < size; ++p) { 1079 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1080 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1081 } 1082 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1083 } 1084 if (drawHasse) { 1085 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1086 1087 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1088 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1089 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1090 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1091 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1092 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1093 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1094 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1095 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1096 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1097 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1098 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1099 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1100 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1101 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1102 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1103 } 1104 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1105 1106 /* Plot vertices */ 1107 PetscCall(VecGetArray(coordinates, &coords)); 1108 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1109 for (v = vStart; v < vEnd; ++v) { 1110 PetscInt off, dof, d; 1111 PetscBool isLabeled = PETSC_FALSE; 1112 1113 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1114 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1115 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1116 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1117 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1118 for (d = 0; d < dof; ++d) { 1119 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1120 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1121 } 1122 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1123 if (dim == 3) { 1124 PetscReal tmp = tcoords[1]; 1125 tcoords[1] = tcoords[2]; 1126 tcoords[2] = -tmp; 1127 } 1128 for (d = 0; d < dof; ++d) { 1129 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1130 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1131 } 1132 if (drawHasse) color = colors[0 % numColors]; 1133 else color = colors[rank % numColors]; 1134 for (l = 0; l < numLabels; ++l) { 1135 PetscInt val; 1136 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1137 if (val >= 0) { 1138 color = lcolors[l % numLColors]; 1139 isLabeled = PETSC_TRUE; 1140 break; 1141 } 1142 } 1143 if (drawNumbers[0]) { 1144 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1145 } else if (drawColors[0]) { 1146 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1147 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1148 } 1149 PetscCall(VecRestoreArray(coordinates, &coords)); 1150 PetscCall(PetscViewerFlush(viewer)); 1151 /* Plot edges */ 1152 if (plotEdges) { 1153 PetscCall(VecGetArray(coordinates, &coords)); 1154 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1155 for (e = eStart; e < eEnd; ++e) { 1156 const PetscInt *cone; 1157 PetscInt coneSize, offA, offB, dof, d; 1158 1159 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1160 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1161 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1162 PetscCall(DMPlexGetCone(dm, e, &cone)); 1163 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1164 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1165 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1166 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1167 for (d = 0; d < dof; ++d) { 1168 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1169 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1170 } 1171 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1172 if (dim == 3) { 1173 PetscReal tmp = tcoords[1]; 1174 tcoords[1] = tcoords[2]; 1175 tcoords[2] = -tmp; 1176 } 1177 for (d = 0; d < dof; ++d) { 1178 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1179 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1180 } 1181 if (drawHasse) color = colors[1 % numColors]; 1182 else color = colors[rank % numColors]; 1183 for (l = 0; l < numLabels; ++l) { 1184 PetscInt val; 1185 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1186 if (val >= 0) { 1187 color = lcolors[l % numLColors]; 1188 break; 1189 } 1190 } 1191 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1192 } 1193 PetscCall(VecRestoreArray(coordinates, &coords)); 1194 PetscCall(PetscViewerFlush(viewer)); 1195 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1196 } 1197 /* Plot cells */ 1198 if (dim == 3 || !drawNumbers[1]) { 1199 for (e = eStart; e < eEnd; ++e) { 1200 const PetscInt *cone; 1201 1202 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1203 color = colors[rank % numColors]; 1204 for (l = 0; l < numLabels; ++l) { 1205 PetscInt val; 1206 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1207 if (val >= 0) { 1208 color = lcolors[l % numLColors]; 1209 break; 1210 } 1211 } 1212 PetscCall(DMPlexGetCone(dm, e, &cone)); 1213 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1214 } 1215 } else { 1216 DMPolytopeType ct; 1217 1218 /* Drawing a 2D polygon */ 1219 for (c = cStart; c < cEnd; ++c) { 1220 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1221 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1222 if (DMPolytopeTypeIsHybrid(ct)) { 1223 const PetscInt *cone; 1224 PetscInt coneSize, e; 1225 1226 PetscCall(DMPlexGetCone(dm, c, &cone)); 1227 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1228 for (e = 0; e < coneSize; ++e) { 1229 const PetscInt *econe; 1230 1231 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1232 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)); 1233 } 1234 } else { 1235 PetscInt *closure = NULL; 1236 PetscInt closureSize, Nv = 0, v; 1237 1238 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1239 for (p = 0; p < closureSize * 2; p += 2) { 1240 const PetscInt point = closure[p]; 1241 1242 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1243 } 1244 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1245 for (v = 0; v <= Nv; ++v) { 1246 const PetscInt vertex = closure[v % Nv]; 1247 1248 if (v > 0) { 1249 if (plotEdges) { 1250 const PetscInt *edge; 1251 PetscInt endpoints[2], ne; 1252 1253 endpoints[0] = closure[v - 1]; 1254 endpoints[1] = vertex; 1255 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1256 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1257 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1258 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1259 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1260 } 1261 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1262 } 1263 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1264 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1265 } 1266 } 1267 } 1268 for (c = cStart; c < cEnd; ++c) { 1269 double ccoords[3] = {0.0, 0.0, 0.0}; 1270 PetscBool isLabeled = PETSC_FALSE; 1271 PetscScalar *cellCoords = NULL; 1272 const PetscScalar *array; 1273 PetscInt numCoords, cdim, d; 1274 PetscBool isDG; 1275 1276 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1277 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1278 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1279 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1280 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1281 for (p = 0; p < numCoords / cdim; ++p) { 1282 for (d = 0; d < cdim; ++d) { 1283 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1284 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1285 } 1286 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1287 if (cdim == 3) { 1288 PetscReal tmp = tcoords[1]; 1289 tcoords[1] = tcoords[2]; 1290 tcoords[2] = -tmp; 1291 } 1292 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1293 } 1294 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1295 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1296 for (d = 0; d < cdim; ++d) { 1297 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1298 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1299 } 1300 if (drawHasse) color = colors[depth % numColors]; 1301 else color = colors[rank % numColors]; 1302 for (l = 0; l < numLabels; ++l) { 1303 PetscInt val; 1304 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1305 if (val >= 0) { 1306 color = lcolors[l % numLColors]; 1307 isLabeled = PETSC_TRUE; 1308 break; 1309 } 1310 } 1311 if (drawNumbers[dim]) { 1312 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1313 } else if (drawColors[dim]) { 1314 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1315 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1316 } 1317 if (drawHasse) { 1318 int height = 0; 1319 1320 color = colors[depth % numColors]; 1321 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1322 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1323 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1324 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1325 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1326 1327 if (depth > 2) { 1328 color = colors[1 % numColors]; 1329 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1330 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1331 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1332 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1333 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1334 } 1335 1336 color = colors[1 % numColors]; 1337 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1338 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1339 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1340 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1341 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1342 1343 color = colors[0 % numColors]; 1344 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1345 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1346 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1347 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1348 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1349 1350 for (p = pStart; p < pEnd; ++p) { 1351 const PetscInt *cone; 1352 PetscInt coneSize, cp; 1353 1354 PetscCall(DMPlexGetCone(dm, p, &cone)); 1355 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1356 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1357 } 1358 } 1359 PetscCall(PetscViewerFlush(viewer)); 1360 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1361 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1362 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1363 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1364 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1365 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1366 PetscCall(PetscFree3(names, colors, lcolors)); 1367 PetscCall(PetscBTDestroy(&wp)); 1368 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1369 Vec cown, acown; 1370 VecScatter sct; 1371 ISLocalToGlobalMapping g2l; 1372 IS gid, acis; 1373 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1374 MPI_Group ggroup, ngroup; 1375 PetscScalar *array, nid; 1376 const PetscInt *idxs; 1377 PetscInt *idxs2, *start, *adjacency, *work; 1378 PetscInt64 lm[3], gm[3]; 1379 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1380 PetscMPIInt d1, d2, rank; 1381 1382 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1383 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1384 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1385 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1386 #endif 1387 if (ncomm != MPI_COMM_NULL) { 1388 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1389 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1390 d1 = 0; 1391 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1392 nid = d2; 1393 PetscCallMPI(MPI_Group_free(&ggroup)); 1394 PetscCallMPI(MPI_Group_free(&ngroup)); 1395 PetscCallMPI(MPI_Comm_free(&ncomm)); 1396 } else nid = 0.0; 1397 1398 /* Get connectivity */ 1399 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1400 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1401 1402 /* filter overlapped local cells */ 1403 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1404 PetscCall(ISGetIndices(gid, &idxs)); 1405 PetscCall(ISGetLocalSize(gid, &cum)); 1406 PetscCall(PetscMalloc1(cum, &idxs2)); 1407 for (c = cStart, cum = 0; c < cEnd; c++) { 1408 if (idxs[c - cStart] < 0) continue; 1409 idxs2[cum++] = idxs[c - cStart]; 1410 } 1411 PetscCall(ISRestoreIndices(gid, &idxs)); 1412 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1413 PetscCall(ISDestroy(&gid)); 1414 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1415 1416 /* support for node-aware cell locality */ 1417 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1418 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1419 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1420 PetscCall(VecGetArray(cown, &array)); 1421 for (c = 0; c < numVertices; c++) array[c] = nid; 1422 PetscCall(VecRestoreArray(cown, &array)); 1423 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1424 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1425 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1426 PetscCall(ISDestroy(&acis)); 1427 PetscCall(VecScatterDestroy(&sct)); 1428 PetscCall(VecDestroy(&cown)); 1429 1430 /* compute edgeCut */ 1431 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1432 PetscCall(PetscMalloc1(cum, &work)); 1433 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1434 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1435 PetscCall(ISDestroy(&gid)); 1436 PetscCall(VecGetArray(acown, &array)); 1437 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1438 PetscInt totl; 1439 1440 totl = start[c + 1] - start[c]; 1441 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1442 for (i = 0; i < totl; i++) { 1443 if (work[i] < 0) { 1444 ect += 1; 1445 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1446 } 1447 } 1448 } 1449 PetscCall(PetscFree(work)); 1450 PetscCall(VecRestoreArray(acown, &array)); 1451 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1452 lm[1] = -numVertices; 1453 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1454 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1455 lm[0] = ect; /* edgeCut */ 1456 lm[1] = ectn; /* node-aware edgeCut */ 1457 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1458 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1459 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1460 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1461 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1462 #else 1463 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1464 #endif 1465 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1466 PetscCall(PetscFree(start)); 1467 PetscCall(PetscFree(adjacency)); 1468 PetscCall(VecDestroy(&acown)); 1469 } else { 1470 const char *name; 1471 PetscInt *sizes, *hybsizes, *ghostsizes; 1472 PetscInt locDepth, depth, cellHeight, dim, d; 1473 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1474 PetscInt numLabels, l, maxSize = 17; 1475 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1476 MPI_Comm comm; 1477 PetscMPIInt size, rank; 1478 1479 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1480 PetscCallMPI(MPI_Comm_size(comm, &size)); 1481 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1482 PetscCall(DMGetDimension(dm, &dim)); 1483 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1484 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1485 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1486 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1487 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1488 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1489 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1490 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1491 gcNum = gcEnd - gcStart; 1492 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1493 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1494 for (d = 0; d <= depth; d++) { 1495 PetscInt Nc[2] = {0, 0}, ict; 1496 1497 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1498 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1499 ict = ct0; 1500 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1501 ct0 = (DMPolytopeType)ict; 1502 for (p = pStart; p < pEnd; ++p) { 1503 DMPolytopeType ct; 1504 1505 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1506 if (ct == ct0) ++Nc[0]; 1507 else ++Nc[1]; 1508 } 1509 if (size < maxSize) { 1510 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1511 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1512 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1513 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1514 for (p = 0; p < size; ++p) { 1515 if (rank == 0) { 1516 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1517 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1518 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1519 } 1520 } 1521 } else { 1522 PetscInt locMinMax[2]; 1523 1524 locMinMax[0] = Nc[0] + Nc[1]; 1525 locMinMax[1] = Nc[0] + Nc[1]; 1526 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1527 locMinMax[0] = Nc[1]; 1528 locMinMax[1] = Nc[1]; 1529 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1530 if (d == depth) { 1531 locMinMax[0] = gcNum; 1532 locMinMax[1] = gcNum; 1533 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1534 } 1535 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1536 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1537 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1538 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1539 } 1540 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1541 } 1542 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1543 { 1544 const PetscReal *maxCell; 1545 const PetscReal *L; 1546 PetscBool localized; 1547 1548 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1549 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1550 if (L || localized) { 1551 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1552 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1553 if (L) { 1554 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1555 for (d = 0; d < dim; ++d) { 1556 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1557 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1558 } 1559 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1560 } 1561 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1562 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1563 } 1564 } 1565 PetscCall(DMGetNumLabels(dm, &numLabels)); 1566 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1567 for (l = 0; l < numLabels; ++l) { 1568 DMLabel label; 1569 const char *name; 1570 PetscInt *values; 1571 PetscInt numValues, v; 1572 1573 PetscCall(DMGetLabelName(dm, l, &name)); 1574 PetscCall(DMGetLabel(dm, name, &label)); 1575 PetscCall(DMLabelGetNumValues(label, &numValues)); 1576 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1577 1578 { // Extract array of DMLabel values so it can be sorted 1579 IS is_values; 1580 const PetscInt *is_values_local = NULL; 1581 1582 PetscCall(DMLabelGetValueIS(label, &is_values)); 1583 PetscCall(ISGetIndices(is_values, &is_values_local)); 1584 PetscCall(PetscMalloc1(numValues, &values)); 1585 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1586 PetscCall(PetscSortInt(numValues, values)); 1587 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1588 PetscCall(ISDestroy(&is_values)); 1589 } 1590 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1591 for (v = 0; v < numValues; ++v) { 1592 PetscInt size; 1593 1594 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1595 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1596 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1597 } 1598 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1599 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1600 PetscCall(PetscFree(values)); 1601 } 1602 { 1603 char **labelNames; 1604 PetscInt Nl = numLabels; 1605 PetscBool flg; 1606 1607 PetscCall(PetscMalloc1(Nl, &labelNames)); 1608 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1609 for (l = 0; l < Nl; ++l) { 1610 DMLabel label; 1611 1612 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1613 if (flg) { 1614 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1615 PetscCall(DMLabelView(label, viewer)); 1616 } 1617 PetscCall(PetscFree(labelNames[l])); 1618 } 1619 PetscCall(PetscFree(labelNames)); 1620 } 1621 /* If no fields are specified, people do not want to see adjacency */ 1622 if (dm->Nf) { 1623 PetscInt f; 1624 1625 for (f = 0; f < dm->Nf; ++f) { 1626 const char *name; 1627 1628 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1629 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1630 PetscCall(PetscViewerASCIIPushTab(viewer)); 1631 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1632 if (dm->fields[f].adjacency[0]) { 1633 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1634 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1635 } else { 1636 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1637 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1638 } 1639 PetscCall(PetscViewerASCIIPopTab(viewer)); 1640 } 1641 } 1642 PetscCall(DMGetCoarseDM(dm, &cdm)); 1643 if (cdm) { 1644 PetscCall(PetscViewerASCIIPushTab(viewer)); 1645 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1646 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1647 PetscCall(PetscViewerASCIIPopTab(viewer)); 1648 } 1649 } 1650 PetscFunctionReturn(PETSC_SUCCESS); 1651 } 1652 1653 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1654 { 1655 DMPolytopeType ct; 1656 PetscMPIInt rank; 1657 PetscInt cdim; 1658 1659 PetscFunctionBegin; 1660 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1661 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1662 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1663 switch (ct) { 1664 case DM_POLYTOPE_SEGMENT: 1665 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1666 switch (cdim) { 1667 case 1: { 1668 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1669 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1670 1671 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1672 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1673 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1674 } break; 1675 case 2: { 1676 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1677 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1678 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1679 1680 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1681 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)); 1682 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)); 1683 } break; 1684 default: 1685 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1686 } 1687 break; 1688 case DM_POLYTOPE_TRIANGLE: 1689 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)); 1690 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1691 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1692 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1693 break; 1694 case DM_POLYTOPE_QUADRILATERAL: 1695 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)); 1696 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)); 1697 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1698 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1699 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1700 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1701 break; 1702 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1703 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)); 1704 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)); 1705 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1706 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1707 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1708 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1709 break; 1710 case DM_POLYTOPE_FV_GHOST: 1711 break; 1712 default: 1713 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1714 } 1715 PetscFunctionReturn(PETSC_SUCCESS); 1716 } 1717 1718 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1719 { 1720 PetscReal centroid[2] = {0., 0.}; 1721 PetscMPIInt rank; 1722 PetscMPIInt fillColor; 1723 1724 PetscFunctionBegin; 1725 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1726 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1727 for (PetscInt v = 0; v < Nv; ++v) { 1728 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1729 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1730 } 1731 for (PetscInt e = 0; e < Nv; ++e) { 1732 refCoords[0] = refVertices[e * 2 + 0]; 1733 refCoords[1] = refVertices[e * 2 + 1]; 1734 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1735 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1736 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1737 } 1738 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1739 for (PetscInt d = 0; d < edgeDiv; ++d) { 1740 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)); 1741 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1742 } 1743 } 1744 PetscFunctionReturn(PETSC_SUCCESS); 1745 } 1746 1747 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1748 { 1749 DMPolytopeType ct; 1750 1751 PetscFunctionBegin; 1752 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1753 switch (ct) { 1754 case DM_POLYTOPE_TRIANGLE: { 1755 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1756 1757 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1758 } break; 1759 case DM_POLYTOPE_QUADRILATERAL: { 1760 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1761 1762 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1763 } break; 1764 default: 1765 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1766 } 1767 PetscFunctionReturn(PETSC_SUCCESS); 1768 } 1769 1770 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1771 { 1772 PetscDraw draw; 1773 DM cdm; 1774 PetscSection coordSection; 1775 Vec coordinates; 1776 PetscReal xyl[3], xyr[3]; 1777 PetscReal *refCoords, *edgeCoords; 1778 PetscBool isnull, drawAffine; 1779 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1780 1781 PetscFunctionBegin; 1782 PetscCall(DMGetCoordinateDim(dm, &dim)); 1783 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1784 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1785 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1786 edgeDiv = cDegree + 1; 1787 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1788 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1789 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1790 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1791 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1792 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1793 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1794 1795 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1796 PetscCall(PetscDrawIsNull(draw, &isnull)); 1797 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1798 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1799 1800 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1801 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1802 PetscCall(PetscDrawClear(draw)); 1803 1804 for (c = cStart; c < cEnd; ++c) { 1805 PetscScalar *coords = NULL; 1806 const PetscScalar *coords_arr; 1807 PetscInt numCoords; 1808 PetscBool isDG; 1809 1810 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1811 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1812 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1813 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1814 } 1815 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1816 PetscCall(PetscDrawFlush(draw)); 1817 PetscCall(PetscDrawPause(draw)); 1818 PetscCall(PetscDrawSave(draw)); 1819 PetscFunctionReturn(PETSC_SUCCESS); 1820 } 1821 1822 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1823 { 1824 DM odm = dm, rdm = dm, cdm; 1825 PetscFE fe; 1826 PetscSpace sp; 1827 PetscClassId id; 1828 PetscInt degree; 1829 PetscBool hoView = PETSC_TRUE; 1830 1831 PetscFunctionBegin; 1832 PetscObjectOptionsBegin((PetscObject)dm); 1833 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1834 PetscOptionsEnd(); 1835 PetscCall(PetscObjectReference((PetscObject)dm)); 1836 *hdm = dm; 1837 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1838 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1839 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1840 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1841 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1842 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1843 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1844 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1845 DM cdm, rcdm; 1846 Mat In; 1847 Vec cl, rcl; 1848 1849 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1850 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1851 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1852 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1853 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1854 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1855 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1856 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1857 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1858 PetscCall(MatMult(In, cl, rcl)); 1859 PetscCall(MatDestroy(&In)); 1860 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1861 PetscCall(DMDestroy(&odm)); 1862 odm = rdm; 1863 } 1864 *hdm = rdm; 1865 PetscFunctionReturn(PETSC_SUCCESS); 1866 } 1867 1868 #if defined(PETSC_HAVE_EXODUSII) 1869 #include <exodusII.h> 1870 #include <petscviewerexodusii.h> 1871 #endif 1872 1873 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1874 { 1875 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1876 char name[PETSC_MAX_PATH_LEN]; 1877 1878 PetscFunctionBegin; 1879 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1880 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1881 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1882 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1883 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1884 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1885 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1886 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1887 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1888 if (iascii) { 1889 PetscViewerFormat format; 1890 PetscCall(PetscViewerGetFormat(viewer, &format)); 1891 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1892 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1893 } else if (ishdf5) { 1894 #if defined(PETSC_HAVE_HDF5) 1895 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1896 #else 1897 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1898 #endif 1899 } else if (isvtk) { 1900 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1901 } else if (isdraw) { 1902 DM hdm; 1903 1904 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1905 PetscCall(DMPlexView_Draw(hdm, viewer)); 1906 PetscCall(DMDestroy(&hdm)); 1907 } else if (isglvis) { 1908 PetscCall(DMPlexView_GLVis(dm, viewer)); 1909 #if defined(PETSC_HAVE_EXODUSII) 1910 } else if (isexodus) { 1911 /* 1912 exodusII requires that all sets be part of exactly one cell set. 1913 If the dm does not have a "Cell Sets" label defined, we create one 1914 with ID 1, containing all cells. 1915 Note that if the Cell Sets label is defined but does not cover all cells, 1916 we may still have a problem. This should probably be checked here or in the viewer; 1917 */ 1918 PetscInt numCS; 1919 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1920 if (!numCS) { 1921 PetscInt cStart, cEnd, c; 1922 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1923 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1924 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1925 } 1926 PetscCall(DMView_PlexExodusII(dm, viewer)); 1927 #endif 1928 #if defined(PETSC_HAVE_CGNS) 1929 } else if (iscgns) { 1930 PetscCall(DMView_PlexCGNS(dm, viewer)); 1931 #endif 1932 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1933 /* Optionally view the partition */ 1934 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1935 if (flg) { 1936 Vec ranks; 1937 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1938 PetscCall(VecView(ranks, viewer)); 1939 PetscCall(VecDestroy(&ranks)); 1940 } 1941 /* Optionally view a label */ 1942 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1943 if (flg) { 1944 DMLabel label; 1945 Vec val; 1946 1947 PetscCall(DMGetLabel(dm, name, &label)); 1948 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1949 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1950 PetscCall(VecView(val, viewer)); 1951 PetscCall(VecDestroy(&val)); 1952 } 1953 PetscFunctionReturn(PETSC_SUCCESS); 1954 } 1955 1956 /*@ 1957 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1958 1959 Collective 1960 1961 Input Parameters: 1962 + dm - The `DM` whose topology is to be saved 1963 - viewer - The `PetscViewer` to save it in 1964 1965 Level: advanced 1966 1967 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1968 @*/ 1969 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1970 { 1971 PetscBool ishdf5; 1972 1973 PetscFunctionBegin; 1974 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1975 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1976 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1977 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1978 if (ishdf5) { 1979 #if defined(PETSC_HAVE_HDF5) 1980 PetscViewerFormat format; 1981 PetscCall(PetscViewerGetFormat(viewer, &format)); 1982 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1983 IS globalPointNumbering; 1984 1985 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1986 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1987 PetscCall(ISDestroy(&globalPointNumbering)); 1988 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1989 #else 1990 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1991 #endif 1992 } 1993 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1994 PetscFunctionReturn(PETSC_SUCCESS); 1995 } 1996 1997 /*@ 1998 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 1999 2000 Collective 2001 2002 Input Parameters: 2003 + dm - The `DM` whose coordinates are to be saved 2004 - viewer - The `PetscViewer` for saving 2005 2006 Level: advanced 2007 2008 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2009 @*/ 2010 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2011 { 2012 PetscBool ishdf5; 2013 2014 PetscFunctionBegin; 2015 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2016 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2017 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2018 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2019 if (ishdf5) { 2020 #if defined(PETSC_HAVE_HDF5) 2021 PetscViewerFormat format; 2022 PetscCall(PetscViewerGetFormat(viewer, &format)); 2023 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2024 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2025 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2026 #else 2027 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2028 #endif 2029 } 2030 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2031 PetscFunctionReturn(PETSC_SUCCESS); 2032 } 2033 2034 /*@ 2035 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2036 2037 Collective 2038 2039 Input Parameters: 2040 + dm - The `DM` whose labels are to be saved 2041 - viewer - The `PetscViewer` for saving 2042 2043 Level: advanced 2044 2045 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2046 @*/ 2047 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2048 { 2049 PetscBool ishdf5; 2050 2051 PetscFunctionBegin; 2052 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2053 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2054 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2055 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2056 if (ishdf5) { 2057 #if defined(PETSC_HAVE_HDF5) 2058 IS globalPointNumbering; 2059 PetscViewerFormat format; 2060 2061 PetscCall(PetscViewerGetFormat(viewer, &format)); 2062 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2063 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2064 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2065 PetscCall(ISDestroy(&globalPointNumbering)); 2066 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 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_LabelsView, viewer, 0, 0, 0)); 2072 PetscFunctionReturn(PETSC_SUCCESS); 2073 } 2074 2075 /*@ 2076 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2077 2078 Collective 2079 2080 Input Parameters: 2081 + dm - The `DM` that contains the topology on which the section to be saved is defined 2082 . viewer - The `PetscViewer` for saving 2083 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2084 2085 Level: advanced 2086 2087 Notes: 2088 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. 2089 2090 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 (or in case `sectiondm` is `NULL`) 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. 2091 2092 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2093 @*/ 2094 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2095 { 2096 PetscBool ishdf5; 2097 2098 PetscFunctionBegin; 2099 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2100 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2101 if (!sectiondm) sectiondm = dm; 2102 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2103 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2104 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2105 if (ishdf5) { 2106 #if defined(PETSC_HAVE_HDF5) 2107 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2108 #else 2109 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2110 #endif 2111 } 2112 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2113 PetscFunctionReturn(PETSC_SUCCESS); 2114 } 2115 2116 /*@ 2117 DMPlexGlobalVectorView - Saves a global vector 2118 2119 Collective 2120 2121 Input Parameters: 2122 + dm - The `DM` that represents the topology 2123 . viewer - The `PetscViewer` to save data with 2124 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2125 - vec - The global vector to be saved 2126 2127 Level: advanced 2128 2129 Notes: 2130 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 (or in case `sectiondm` is `NULL`) 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. 2131 2132 Calling sequence: 2133 .vb 2134 DMCreate(PETSC_COMM_WORLD, &dm); 2135 DMSetType(dm, DMPLEX); 2136 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2137 DMClone(dm, §iondm); 2138 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2139 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2140 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2141 PetscSectionSetChart(section, pStart, pEnd); 2142 PetscSectionSetUp(section); 2143 DMSetLocalSection(sectiondm, section); 2144 PetscSectionDestroy(§ion); 2145 DMGetGlobalVector(sectiondm, &vec); 2146 PetscObjectSetName((PetscObject)vec, "vec_name"); 2147 DMPlexTopologyView(dm, viewer); 2148 DMPlexSectionView(dm, viewer, sectiondm); 2149 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2150 DMRestoreGlobalVector(sectiondm, &vec); 2151 DMDestroy(§iondm); 2152 DMDestroy(&dm); 2153 .ve 2154 2155 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2156 @*/ 2157 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2158 { 2159 PetscBool ishdf5; 2160 2161 PetscFunctionBegin; 2162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2163 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2164 if (!sectiondm) sectiondm = dm; 2165 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2166 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2167 /* Check consistency */ 2168 { 2169 PetscSection section; 2170 PetscBool includesConstraints; 2171 PetscInt m, m1; 2172 2173 PetscCall(VecGetLocalSize(vec, &m1)); 2174 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2175 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2176 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2177 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2178 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2179 } 2180 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2181 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2182 if (ishdf5) { 2183 #if defined(PETSC_HAVE_HDF5) 2184 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2185 #else 2186 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2187 #endif 2188 } 2189 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2190 PetscFunctionReturn(PETSC_SUCCESS); 2191 } 2192 2193 /*@ 2194 DMPlexLocalVectorView - Saves a local vector 2195 2196 Collective 2197 2198 Input Parameters: 2199 + dm - The `DM` that represents the topology 2200 . viewer - The `PetscViewer` to save data with 2201 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2202 - vec - The local vector to be saved 2203 2204 Level: advanced 2205 2206 Note: 2207 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 (or in case `sectiondm` is `NULL`) 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. 2208 2209 Calling sequence: 2210 .vb 2211 DMCreate(PETSC_COMM_WORLD, &dm); 2212 DMSetType(dm, DMPLEX); 2213 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2214 DMClone(dm, §iondm); 2215 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2216 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2217 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2218 PetscSectionSetChart(section, pStart, pEnd); 2219 PetscSectionSetUp(section); 2220 DMSetLocalSection(sectiondm, section); 2221 DMGetLocalVector(sectiondm, &vec); 2222 PetscObjectSetName((PetscObject)vec, "vec_name"); 2223 DMPlexTopologyView(dm, viewer); 2224 DMPlexSectionView(dm, viewer, sectiondm); 2225 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2226 DMRestoreLocalVector(sectiondm, &vec); 2227 DMDestroy(§iondm); 2228 DMDestroy(&dm); 2229 .ve 2230 2231 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2232 @*/ 2233 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2234 { 2235 PetscBool ishdf5; 2236 2237 PetscFunctionBegin; 2238 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2239 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2240 if (!sectiondm) sectiondm = dm; 2241 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2242 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2243 /* Check consistency */ 2244 { 2245 PetscSection section; 2246 PetscBool includesConstraints; 2247 PetscInt m, m1; 2248 2249 PetscCall(VecGetLocalSize(vec, &m1)); 2250 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2251 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2252 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2253 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2254 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2255 } 2256 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2257 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2258 if (ishdf5) { 2259 #if defined(PETSC_HAVE_HDF5) 2260 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2261 #else 2262 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2263 #endif 2264 } 2265 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2266 PetscFunctionReturn(PETSC_SUCCESS); 2267 } 2268 2269 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2270 { 2271 PetscBool ishdf5; 2272 2273 PetscFunctionBegin; 2274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2275 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2276 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2277 if (ishdf5) { 2278 #if defined(PETSC_HAVE_HDF5) 2279 PetscViewerFormat format; 2280 PetscCall(PetscViewerGetFormat(viewer, &format)); 2281 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2282 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2283 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2284 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2285 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2286 PetscFunctionReturn(PETSC_SUCCESS); 2287 #else 2288 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2289 #endif 2290 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2291 } 2292 2293 /*@ 2294 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2295 2296 Collective 2297 2298 Input Parameters: 2299 + dm - The `DM` into which the topology is loaded 2300 - viewer - The `PetscViewer` for the saved topology 2301 2302 Output Parameter: 2303 . 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; 2304 `NULL` if unneeded 2305 2306 Level: advanced 2307 2308 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2309 `PetscViewer`, `PetscSF` 2310 @*/ 2311 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2312 { 2313 PetscBool ishdf5; 2314 2315 PetscFunctionBegin; 2316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2317 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2318 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2319 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2320 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2321 if (ishdf5) { 2322 #if defined(PETSC_HAVE_HDF5) 2323 PetscViewerFormat format; 2324 PetscCall(PetscViewerGetFormat(viewer, &format)); 2325 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2326 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2327 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2328 #else 2329 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2330 #endif 2331 } 2332 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2333 PetscFunctionReturn(PETSC_SUCCESS); 2334 } 2335 2336 /*@ 2337 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2338 2339 Collective 2340 2341 Input Parameters: 2342 + dm - The `DM` into which the coordinates are loaded 2343 . viewer - The `PetscViewer` for the saved coordinates 2344 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2345 2346 Level: advanced 2347 2348 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2349 `PetscSF`, `PetscViewer` 2350 @*/ 2351 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2352 { 2353 PetscBool ishdf5; 2354 2355 PetscFunctionBegin; 2356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2357 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2358 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2359 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2360 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2361 if (ishdf5) { 2362 #if defined(PETSC_HAVE_HDF5) 2363 PetscViewerFormat format; 2364 PetscCall(PetscViewerGetFormat(viewer, &format)); 2365 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2366 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2367 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2368 #else 2369 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2370 #endif 2371 } 2372 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2373 PetscFunctionReturn(PETSC_SUCCESS); 2374 } 2375 2376 /*@ 2377 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2378 2379 Collective 2380 2381 Input Parameters: 2382 + dm - The `DM` into which the labels are loaded 2383 . viewer - The `PetscViewer` for the saved labels 2384 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2385 2386 Level: advanced 2387 2388 Note: 2389 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2390 2391 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2392 `PetscSF`, `PetscViewer` 2393 @*/ 2394 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2395 { 2396 PetscBool ishdf5; 2397 2398 PetscFunctionBegin; 2399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2400 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2401 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2402 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2403 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2404 if (ishdf5) { 2405 #if defined(PETSC_HAVE_HDF5) 2406 PetscViewerFormat format; 2407 2408 PetscCall(PetscViewerGetFormat(viewer, &format)); 2409 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2410 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2411 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2412 #else 2413 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2414 #endif 2415 } 2416 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2417 PetscFunctionReturn(PETSC_SUCCESS); 2418 } 2419 2420 /*@ 2421 DMPlexSectionLoad - Loads section into a `DMPLEX` 2422 2423 Collective 2424 2425 Input Parameters: 2426 + dm - The `DM` that represents the topology 2427 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2428 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2429 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2430 2431 Output Parameters: 2432 + 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) 2433 - 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) 2434 2435 Level: advanced 2436 2437 Notes: 2438 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. 2439 2440 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 (or in case `sectiondm` is `NULL`) 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. 2441 2442 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. 2443 2444 Example using 2 processes: 2445 .vb 2446 NX (number of points on dm): 4 2447 sectionA : the on-disk section 2448 vecA : a vector associated with sectionA 2449 sectionB : sectiondm's local section constructed in this function 2450 vecB (local) : a vector associated with sectiondm's local section 2451 vecB (global) : a vector associated with sectiondm's global section 2452 2453 rank 0 rank 1 2454 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2455 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2456 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2457 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2458 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2459 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2460 sectionB->atlasDof : 1 0 1 | 1 3 2461 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2462 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2463 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2464 .ve 2465 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2466 2467 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2468 @*/ 2469 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2470 { 2471 PetscBool ishdf5; 2472 2473 PetscFunctionBegin; 2474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2475 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2476 if (!sectiondm) sectiondm = dm; 2477 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2478 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2479 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2480 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2481 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2482 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2483 if (ishdf5) { 2484 #if defined(PETSC_HAVE_HDF5) 2485 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2486 #else 2487 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2488 #endif 2489 } 2490 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2491 PetscFunctionReturn(PETSC_SUCCESS); 2492 } 2493 2494 /*@ 2495 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2496 2497 Collective 2498 2499 Input Parameters: 2500 + dm - The `DM` that represents the topology 2501 . viewer - The `PetscViewer` that represents the on-disk vector data 2502 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2503 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2504 - vec - The global vector to set values of 2505 2506 Level: advanced 2507 2508 Notes: 2509 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 (or in case `sectiondm` is `NULL`) 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. 2510 2511 Calling sequence: 2512 .vb 2513 DMCreate(PETSC_COMM_WORLD, &dm); 2514 DMSetType(dm, DMPLEX); 2515 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2516 DMPlexTopologyLoad(dm, viewer, &sfX); 2517 DMClone(dm, §iondm); 2518 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2519 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2520 DMGetGlobalVector(sectiondm, &vec); 2521 PetscObjectSetName((PetscObject)vec, "vec_name"); 2522 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2523 DMRestoreGlobalVector(sectiondm, &vec); 2524 PetscSFDestroy(&gsf); 2525 PetscSFDestroy(&sfX); 2526 DMDestroy(§iondm); 2527 DMDestroy(&dm); 2528 .ve 2529 2530 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2531 `PetscSF`, `PetscViewer` 2532 @*/ 2533 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2534 { 2535 PetscBool ishdf5; 2536 2537 PetscFunctionBegin; 2538 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2539 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2540 if (!sectiondm) sectiondm = dm; 2541 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2542 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2543 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2544 /* Check consistency */ 2545 { 2546 PetscSection section; 2547 PetscBool includesConstraints; 2548 PetscInt m, m1; 2549 2550 PetscCall(VecGetLocalSize(vec, &m1)); 2551 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2552 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2553 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2554 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2555 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2556 } 2557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2558 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2559 if (ishdf5) { 2560 #if defined(PETSC_HAVE_HDF5) 2561 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2562 #else 2563 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2564 #endif 2565 } 2566 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2567 PetscFunctionReturn(PETSC_SUCCESS); 2568 } 2569 2570 /*@ 2571 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2572 2573 Collective 2574 2575 Input Parameters: 2576 + dm - The `DM` that represents the topology 2577 . viewer - The `PetscViewer` that represents the on-disk vector data 2578 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2579 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2580 - vec - The local vector to set values of 2581 2582 Level: advanced 2583 2584 Notes: 2585 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 (or in case `sectiondm` is `NULL`) 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. 2586 2587 Calling sequence: 2588 .vb 2589 DMCreate(PETSC_COMM_WORLD, &dm); 2590 DMSetType(dm, DMPLEX); 2591 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2592 DMPlexTopologyLoad(dm, viewer, &sfX); 2593 DMClone(dm, §iondm); 2594 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2595 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2596 DMGetLocalVector(sectiondm, &vec); 2597 PetscObjectSetName((PetscObject)vec, "vec_name"); 2598 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2599 DMRestoreLocalVector(sectiondm, &vec); 2600 PetscSFDestroy(&lsf); 2601 PetscSFDestroy(&sfX); 2602 DMDestroy(§iondm); 2603 DMDestroy(&dm); 2604 .ve 2605 2606 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2607 `PetscSF`, `PetscViewer` 2608 @*/ 2609 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2610 { 2611 PetscBool ishdf5; 2612 2613 PetscFunctionBegin; 2614 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2615 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2616 if (!sectiondm) sectiondm = dm; 2617 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2618 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2619 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2620 /* Check consistency */ 2621 { 2622 PetscSection section; 2623 PetscBool includesConstraints; 2624 PetscInt m, m1; 2625 2626 PetscCall(VecGetLocalSize(vec, &m1)); 2627 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2628 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2629 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2630 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2631 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2632 } 2633 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2634 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2635 if (ishdf5) { 2636 #if defined(PETSC_HAVE_HDF5) 2637 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2638 #else 2639 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2640 #endif 2641 } 2642 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2643 PetscFunctionReturn(PETSC_SUCCESS); 2644 } 2645 2646 PetscErrorCode DMDestroy_Plex(DM dm) 2647 { 2648 DM_Plex *mesh = (DM_Plex *)dm->data; 2649 2650 PetscFunctionBegin; 2651 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2652 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2653 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2654 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2655 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2656 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2657 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2658 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2659 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2660 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2661 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2662 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2663 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2664 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2665 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2666 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2667 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2668 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2669 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2670 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2671 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2672 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2673 PetscCall(PetscFree(mesh->cones)); 2674 PetscCall(PetscFree(mesh->coneOrientations)); 2675 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2676 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2677 PetscCall(PetscFree(mesh->supports)); 2678 PetscCall(PetscFree(mesh->cellTypes)); 2679 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2680 PetscCall(PetscFree(mesh->tetgenOpts)); 2681 PetscCall(PetscFree(mesh->triangleOpts)); 2682 PetscCall(PetscFree(mesh->transformType)); 2683 PetscCall(PetscFree(mesh->distributionName)); 2684 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2685 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2686 PetscCall(ISDestroy(&mesh->subpointIS)); 2687 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2688 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2689 if (mesh->periodic.face_sfs) { 2690 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2691 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2692 } 2693 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2694 if (mesh->periodic.periodic_points) { 2695 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2696 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2697 } 2698 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2699 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2700 PetscCall(ISDestroy(&mesh->anchorIS)); 2701 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2702 PetscCall(PetscFree(mesh->parents)); 2703 PetscCall(PetscFree(mesh->childIDs)); 2704 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2705 PetscCall(PetscFree(mesh->children)); 2706 PetscCall(DMDestroy(&mesh->referenceTree)); 2707 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2708 PetscCall(PetscFree(mesh->neighbors)); 2709 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2710 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2711 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2712 PetscCall(PetscFree(mesh)); 2713 PetscFunctionReturn(PETSC_SUCCESS); 2714 } 2715 2716 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2717 { 2718 PetscSection sectionGlobal, sectionLocal; 2719 PetscInt bs = -1, mbs; 2720 PetscInt localSize, localStart = 0; 2721 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2722 MatType mtype; 2723 ISLocalToGlobalMapping ltog; 2724 2725 PetscFunctionBegin; 2726 PetscCall(MatInitializePackage()); 2727 mtype = dm->mattype; 2728 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2729 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2730 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2731 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2732 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2733 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2734 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2735 PetscCall(MatSetType(*J, mtype)); 2736 PetscCall(MatSetFromOptions(*J)); 2737 PetscCall(MatGetBlockSize(*J, &mbs)); 2738 if (mbs > 1) bs = mbs; 2739 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2740 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2741 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2742 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2743 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2744 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2745 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2746 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2747 if (!isShell) { 2748 // There are three states with pblocks, since block starts can have no dofs: 2749 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2750 // TRUE) Block Start: The first entry in a block has been added 2751 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2752 PetscBT blst; 2753 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2754 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2755 const PetscInt *perm = NULL; 2756 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2757 PetscInt pStart, pEnd, dof, cdof, num_fields; 2758 2759 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2760 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2761 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2762 2763 PetscCall(PetscCalloc1(localSize, &pblocks)); 2764 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2765 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2766 // We need to process in the permuted order to get block sizes right 2767 for (PetscInt point = pStart; point < pEnd; ++point) { 2768 const PetscInt p = perm ? perm[point] : point; 2769 2770 switch (dm->blocking_type) { 2771 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2772 PetscInt bdof, offset; 2773 2774 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2775 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2776 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2777 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2778 if (dof > 0) { 2779 // State change 2780 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2781 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2782 2783 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2784 // Signal block concatenation 2785 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2786 } 2787 dof = dof < 0 ? -(dof + 1) : dof; 2788 bdof = cdof && (dof - cdof) ? 1 : dof; 2789 if (dof) { 2790 if (bs < 0) { 2791 bs = bdof; 2792 } else if (bs != bdof) { 2793 bs = 1; 2794 } 2795 } 2796 } break; 2797 case DM_BLOCKING_FIELD_NODE: { 2798 for (PetscInt field = 0; field < num_fields; field++) { 2799 PetscInt num_comp, bdof, offset; 2800 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2801 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2802 if (dof < 0) continue; 2803 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2804 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2805 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); 2806 PetscInt num_nodes = dof / num_comp; 2807 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2808 // Handle possibly constant block size (unlikely) 2809 bdof = cdof && (dof - cdof) ? 1 : dof; 2810 if (dof) { 2811 if (bs < 0) { 2812 bs = bdof; 2813 } else if (bs != bdof) { 2814 bs = 1; 2815 } 2816 } 2817 } 2818 } break; 2819 } 2820 } 2821 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2822 /* Must have same blocksize on all procs (some might have no points) */ 2823 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2824 bsLocal[1] = bs; 2825 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2826 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2827 else bs = bsMinMax[0]; 2828 bs = PetscMax(1, bs); 2829 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2830 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2831 PetscCall(MatSetBlockSize(*J, bs)); 2832 PetscCall(MatSetUp(*J)); 2833 } else { 2834 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2835 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2836 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2837 } 2838 if (pblocks) { // Consolidate blocks 2839 PetscInt nblocks = 0; 2840 pblocks[0] = PetscAbs(pblocks[0]); 2841 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2842 if (pblocks[i] == 0) continue; 2843 // Negative block size indicates the blocks should be concatenated 2844 if (pblocks[i] < 0) { 2845 pblocks[i] = -pblocks[i]; 2846 pblocks[nblocks - 1] += pblocks[i]; 2847 } else { 2848 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2849 } 2850 for (PetscInt j = 1; j < pblocks[i]; j++) 2851 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 2852 } 2853 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2854 } 2855 PetscCall(PetscFree(pblocks)); 2856 } 2857 PetscCall(MatSetDM(*J, dm)); 2858 PetscFunctionReturn(PETSC_SUCCESS); 2859 } 2860 2861 /*@ 2862 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2863 2864 Not Collective 2865 2866 Input Parameter: 2867 . dm - The `DMPLEX` 2868 2869 Output Parameter: 2870 . subsection - The subdomain section 2871 2872 Level: developer 2873 2874 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2875 @*/ 2876 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2877 { 2878 DM_Plex *mesh = (DM_Plex *)dm->data; 2879 2880 PetscFunctionBegin; 2881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2882 if (!mesh->subdomainSection) { 2883 PetscSection section; 2884 PetscSF sf; 2885 2886 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2887 PetscCall(DMGetLocalSection(dm, §ion)); 2888 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2889 PetscCall(PetscSFDestroy(&sf)); 2890 } 2891 *subsection = mesh->subdomainSection; 2892 PetscFunctionReturn(PETSC_SUCCESS); 2893 } 2894 2895 /*@ 2896 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2897 2898 Not Collective 2899 2900 Input Parameter: 2901 . dm - The `DMPLEX` 2902 2903 Output Parameters: 2904 + pStart - The first mesh point 2905 - pEnd - The upper bound for mesh points 2906 2907 Level: beginner 2908 2909 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2910 @*/ 2911 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2912 { 2913 DM_Plex *mesh = (DM_Plex *)dm->data; 2914 2915 PetscFunctionBegin; 2916 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2917 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2918 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2919 PetscFunctionReturn(PETSC_SUCCESS); 2920 } 2921 2922 /*@ 2923 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2924 2925 Not Collective 2926 2927 Input Parameters: 2928 + dm - The `DMPLEX` 2929 . pStart - The first mesh point 2930 - pEnd - The upper bound for mesh points 2931 2932 Level: beginner 2933 2934 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2935 @*/ 2936 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2937 { 2938 DM_Plex *mesh = (DM_Plex *)dm->data; 2939 2940 PetscFunctionBegin; 2941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2942 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2943 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2944 PetscCall(PetscFree(mesh->cellTypes)); 2945 PetscFunctionReturn(PETSC_SUCCESS); 2946 } 2947 2948 /*@ 2949 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2950 2951 Not Collective 2952 2953 Input Parameters: 2954 + dm - The `DMPLEX` 2955 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2956 2957 Output Parameter: 2958 . size - The cone size for point `p` 2959 2960 Level: beginner 2961 2962 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2963 @*/ 2964 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2965 { 2966 DM_Plex *mesh = (DM_Plex *)dm->data; 2967 2968 PetscFunctionBegin; 2969 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2970 PetscAssertPointer(size, 3); 2971 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2972 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2973 PetscFunctionReturn(PETSC_SUCCESS); 2974 } 2975 2976 /*@ 2977 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2978 2979 Not Collective 2980 2981 Input Parameters: 2982 + dm - The `DMPLEX` 2983 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2984 - size - The cone size for point `p` 2985 2986 Level: beginner 2987 2988 Note: 2989 This should be called after `DMPlexSetChart()`. 2990 2991 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2992 @*/ 2993 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2994 { 2995 DM_Plex *mesh = (DM_Plex *)dm->data; 2996 2997 PetscFunctionBegin; 2998 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2999 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3000 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3001 PetscFunctionReturn(PETSC_SUCCESS); 3002 } 3003 3004 /*@C 3005 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3006 3007 Not Collective 3008 3009 Input Parameters: 3010 + dm - The `DMPLEX` 3011 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3012 3013 Output Parameter: 3014 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3015 3016 Level: beginner 3017 3018 Fortran Notes: 3019 `cone` must be declared with 3020 .vb 3021 PetscInt, pointer :: cone(:) 3022 .ve 3023 3024 You must also call `DMPlexRestoreCone()` after you finish using the array. 3025 `DMPlexRestoreCone()` is not needed/available in C. 3026 3027 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3028 @*/ 3029 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3030 { 3031 DM_Plex *mesh = (DM_Plex *)dm->data; 3032 PetscInt off; 3033 3034 PetscFunctionBegin; 3035 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3036 PetscAssertPointer(cone, 3); 3037 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3038 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3039 PetscFunctionReturn(PETSC_SUCCESS); 3040 } 3041 3042 /*@ 3043 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3044 3045 Not Collective 3046 3047 Input Parameters: 3048 + dm - The `DMPLEX` 3049 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3050 3051 Output Parameters: 3052 + pConesSection - `PetscSection` describing the layout of `pCones` 3053 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3054 3055 Level: intermediate 3056 3057 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3058 @*/ 3059 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3060 { 3061 PetscSection cs, newcs; 3062 PetscInt *cones; 3063 PetscInt *newarr = NULL; 3064 PetscInt n; 3065 3066 PetscFunctionBegin; 3067 PetscCall(DMPlexGetCones(dm, &cones)); 3068 PetscCall(DMPlexGetConeSection(dm, &cs)); 3069 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3070 if (pConesSection) *pConesSection = newcs; 3071 if (pCones) { 3072 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3073 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3074 } 3075 PetscFunctionReturn(PETSC_SUCCESS); 3076 } 3077 3078 /*@ 3079 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3080 3081 Not Collective 3082 3083 Input Parameters: 3084 + dm - The `DMPLEX` 3085 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3086 3087 Output Parameter: 3088 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3089 3090 Level: advanced 3091 3092 Notes: 3093 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3094 3095 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3096 3097 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3098 `DMPlexGetDepth()`, `IS` 3099 @*/ 3100 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3101 { 3102 IS *expandedPointsAll; 3103 PetscInt depth; 3104 3105 PetscFunctionBegin; 3106 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3107 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3108 PetscAssertPointer(expandedPoints, 3); 3109 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3110 *expandedPoints = expandedPointsAll[0]; 3111 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3112 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3113 PetscFunctionReturn(PETSC_SUCCESS); 3114 } 3115 3116 /*@ 3117 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3118 (DAG points of depth 0, i.e., without cones). 3119 3120 Not Collective 3121 3122 Input Parameters: 3123 + dm - The `DMPLEX` 3124 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3125 3126 Output Parameters: 3127 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3128 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3129 - sections - (optional) An array of sections which describe mappings from points to their cone points 3130 3131 Level: advanced 3132 3133 Notes: 3134 Like `DMPlexGetConeTuple()` but recursive. 3135 3136 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. 3137 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3138 3139 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\: 3140 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3141 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3142 3143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3144 `DMPlexGetDepth()`, `PetscSection`, `IS` 3145 @*/ 3146 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3147 { 3148 const PetscInt *arr0 = NULL, *cone = NULL; 3149 PetscInt *arr = NULL, *newarr = NULL; 3150 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3151 IS *expandedPoints_; 3152 PetscSection *sections_; 3153 3154 PetscFunctionBegin; 3155 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3156 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3157 if (depth) PetscAssertPointer(depth, 3); 3158 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3159 if (sections) PetscAssertPointer(sections, 5); 3160 PetscCall(ISGetLocalSize(points, &n)); 3161 PetscCall(ISGetIndices(points, &arr0)); 3162 PetscCall(DMPlexGetDepth(dm, &depth_)); 3163 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3164 PetscCall(PetscCalloc1(depth_, §ions_)); 3165 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3166 for (d = depth_ - 1; d >= 0; d--) { 3167 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3168 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3169 for (i = 0; i < n; i++) { 3170 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3171 if (arr[i] >= start && arr[i] < end) { 3172 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3173 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3174 } else { 3175 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3176 } 3177 } 3178 PetscCall(PetscSectionSetUp(sections_[d])); 3179 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3180 PetscCall(PetscMalloc1(newn, &newarr)); 3181 for (i = 0; i < n; i++) { 3182 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3183 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3184 if (cn > 1) { 3185 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3186 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3187 } else { 3188 newarr[co] = arr[i]; 3189 } 3190 } 3191 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3192 arr = newarr; 3193 n = newn; 3194 } 3195 PetscCall(ISRestoreIndices(points, &arr0)); 3196 *depth = depth_; 3197 if (expandedPoints) *expandedPoints = expandedPoints_; 3198 else { 3199 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3200 PetscCall(PetscFree(expandedPoints_)); 3201 } 3202 if (sections) *sections = sections_; 3203 else { 3204 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3205 PetscCall(PetscFree(sections_)); 3206 } 3207 PetscFunctionReturn(PETSC_SUCCESS); 3208 } 3209 3210 /*@ 3211 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3212 3213 Not Collective 3214 3215 Input Parameters: 3216 + dm - The `DMPLEX` 3217 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3218 3219 Output Parameters: 3220 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3221 . expandedPoints - (optional) An array of recursively expanded cones 3222 - sections - (optional) An array of sections which describe mappings from points to their cone points 3223 3224 Level: advanced 3225 3226 Note: 3227 See `DMPlexGetConeRecursive()` 3228 3229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3230 `DMPlexGetDepth()`, `IS`, `PetscSection` 3231 @*/ 3232 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3233 { 3234 PetscInt d, depth_; 3235 3236 PetscFunctionBegin; 3237 PetscCall(DMPlexGetDepth(dm, &depth_)); 3238 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3239 if (depth) *depth = 0; 3240 if (expandedPoints) { 3241 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3242 PetscCall(PetscFree(*expandedPoints)); 3243 } 3244 if (sections) { 3245 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3246 PetscCall(PetscFree(*sections)); 3247 } 3248 PetscFunctionReturn(PETSC_SUCCESS); 3249 } 3250 3251 /*@ 3252 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 3253 3254 Not Collective 3255 3256 Input Parameters: 3257 + dm - The `DMPLEX` 3258 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3259 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3260 3261 Level: beginner 3262 3263 Note: 3264 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3265 3266 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3267 @*/ 3268 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3269 { 3270 DM_Plex *mesh = (DM_Plex *)dm->data; 3271 PetscInt dof, off, c; 3272 3273 PetscFunctionBegin; 3274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3275 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3276 if (dof) PetscAssertPointer(cone, 3); 3277 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3278 if (PetscDefined(USE_DEBUG)) { 3279 PetscInt pStart, pEnd; 3280 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3281 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); 3282 for (c = 0; c < dof; ++c) { 3283 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); 3284 mesh->cones[off + c] = cone[c]; 3285 } 3286 } else { 3287 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3288 } 3289 PetscFunctionReturn(PETSC_SUCCESS); 3290 } 3291 3292 /*@C 3293 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3294 3295 Not Collective 3296 3297 Input Parameters: 3298 + dm - The `DMPLEX` 3299 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3300 3301 Output Parameter: 3302 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3303 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3304 3305 Level: beginner 3306 3307 Note: 3308 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3309 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3310 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3311 with the identity. 3312 3313 Fortran Notes: 3314 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3315 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3316 3317 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3318 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3319 @*/ 3320 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3321 { 3322 DM_Plex *mesh = (DM_Plex *)dm->data; 3323 PetscInt off; 3324 3325 PetscFunctionBegin; 3326 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3327 if (PetscDefined(USE_DEBUG)) { 3328 PetscInt dof; 3329 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3330 if (dof) PetscAssertPointer(coneOrientation, 3); 3331 } 3332 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3333 3334 *coneOrientation = &mesh->coneOrientations[off]; 3335 PetscFunctionReturn(PETSC_SUCCESS); 3336 } 3337 3338 /*@ 3339 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3340 3341 Not Collective 3342 3343 Input Parameters: 3344 + dm - The `DMPLEX` 3345 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3346 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3347 3348 Level: beginner 3349 3350 Notes: 3351 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3352 3353 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3354 3355 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3356 @*/ 3357 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3358 { 3359 DM_Plex *mesh = (DM_Plex *)dm->data; 3360 PetscInt pStart, pEnd; 3361 PetscInt dof, off, c; 3362 3363 PetscFunctionBegin; 3364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3365 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3366 if (dof) PetscAssertPointer(coneOrientation, 3); 3367 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3368 if (PetscDefined(USE_DEBUG)) { 3369 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3370 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); 3371 for (c = 0; c < dof; ++c) { 3372 PetscInt cdof, o = coneOrientation[c]; 3373 3374 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3375 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); 3376 mesh->coneOrientations[off + c] = o; 3377 } 3378 } else { 3379 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3380 } 3381 PetscFunctionReturn(PETSC_SUCCESS); 3382 } 3383 3384 /*@ 3385 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3386 3387 Not Collective 3388 3389 Input Parameters: 3390 + dm - The `DMPLEX` 3391 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3392 . conePos - The local index in the cone where the point should be put 3393 - conePoint - The mesh point to insert 3394 3395 Level: beginner 3396 3397 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3398 @*/ 3399 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3400 { 3401 DM_Plex *mesh = (DM_Plex *)dm->data; 3402 PetscInt pStart, pEnd; 3403 PetscInt dof, off; 3404 3405 PetscFunctionBegin; 3406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3407 if (PetscDefined(USE_DEBUG)) { 3408 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3409 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); 3410 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); 3411 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3412 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); 3413 } 3414 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3415 mesh->cones[off + conePos] = conePoint; 3416 PetscFunctionReturn(PETSC_SUCCESS); 3417 } 3418 3419 /*@ 3420 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3421 3422 Not Collective 3423 3424 Input Parameters: 3425 + dm - The `DMPLEX` 3426 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3427 . conePos - The local index in the cone where the point should be put 3428 - coneOrientation - The point orientation to insert 3429 3430 Level: beginner 3431 3432 Note: 3433 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3434 3435 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3436 @*/ 3437 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3438 { 3439 DM_Plex *mesh = (DM_Plex *)dm->data; 3440 PetscInt pStart, pEnd; 3441 PetscInt dof, off; 3442 3443 PetscFunctionBegin; 3444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3445 if (PetscDefined(USE_DEBUG)) { 3446 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3447 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); 3448 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3449 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); 3450 } 3451 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3452 mesh->coneOrientations[off + conePos] = coneOrientation; 3453 PetscFunctionReturn(PETSC_SUCCESS); 3454 } 3455 3456 /*@C 3457 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3458 3459 Not collective 3460 3461 Input Parameters: 3462 + dm - The DMPlex 3463 - p - The point, which must lie in the chart set with DMPlexSetChart() 3464 3465 Output Parameters: 3466 + cone - An array of points which are on the in-edges for point `p` 3467 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3468 integer giving the prescription for cone traversal. 3469 3470 Level: beginner 3471 3472 Notes: 3473 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3474 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3475 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3476 with the identity. 3477 3478 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3479 3480 Fortran Notes: 3481 `cone` and `ornt` must be declared with 3482 .vb 3483 PetscInt, pointer :: cone(:) 3484 PetscInt, pointer :: ornt(:) 3485 .ve 3486 3487 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3488 @*/ 3489 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3490 { 3491 DM_Plex *mesh = (DM_Plex *)dm->data; 3492 3493 PetscFunctionBegin; 3494 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3495 if (mesh->tr) { 3496 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3497 } else { 3498 PetscInt off; 3499 if (PetscDefined(USE_DEBUG)) { 3500 PetscInt dof; 3501 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3502 if (dof) { 3503 if (cone) PetscAssertPointer(cone, 3); 3504 if (ornt) PetscAssertPointer(ornt, 4); 3505 } 3506 } 3507 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3508 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3509 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3510 } 3511 PetscFunctionReturn(PETSC_SUCCESS); 3512 } 3513 3514 /*@C 3515 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3516 3517 Not Collective 3518 3519 Input Parameters: 3520 + dm - The DMPlex 3521 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3522 . cone - An array of points which are on the in-edges for point p 3523 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3524 integer giving the prescription for cone traversal. 3525 3526 Level: beginner 3527 3528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3529 @*/ 3530 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3531 { 3532 DM_Plex *mesh = (DM_Plex *)dm->data; 3533 3534 PetscFunctionBegin; 3535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3536 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3537 PetscFunctionReturn(PETSC_SUCCESS); 3538 } 3539 3540 /*@ 3541 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3542 3543 Not Collective 3544 3545 Input Parameters: 3546 + dm - The `DMPLEX` 3547 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3548 3549 Output Parameter: 3550 . size - The support size for point `p` 3551 3552 Level: beginner 3553 3554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3555 @*/ 3556 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3557 { 3558 DM_Plex *mesh = (DM_Plex *)dm->data; 3559 3560 PetscFunctionBegin; 3561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3562 PetscAssertPointer(size, 3); 3563 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3564 PetscFunctionReturn(PETSC_SUCCESS); 3565 } 3566 3567 /*@ 3568 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3569 3570 Not Collective 3571 3572 Input Parameters: 3573 + dm - The `DMPLEX` 3574 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3575 - size - The support size for point `p` 3576 3577 Level: beginner 3578 3579 Note: 3580 This should be called after `DMPlexSetChart()`. 3581 3582 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3583 @*/ 3584 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3585 { 3586 DM_Plex *mesh = (DM_Plex *)dm->data; 3587 3588 PetscFunctionBegin; 3589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3590 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3591 PetscFunctionReturn(PETSC_SUCCESS); 3592 } 3593 3594 /*@C 3595 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3596 3597 Not Collective 3598 3599 Input Parameters: 3600 + dm - The `DMPLEX` 3601 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3602 3603 Output Parameter: 3604 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3605 3606 Level: beginner 3607 3608 Fortran Notes: 3609 `support` must be declared with 3610 .vb 3611 PetscInt, pointer :: support(:) 3612 .ve 3613 3614 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3615 `DMPlexRestoreSupport()` is not needed/available in C. 3616 3617 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3618 @*/ 3619 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3620 { 3621 DM_Plex *mesh = (DM_Plex *)dm->data; 3622 PetscInt off; 3623 3624 PetscFunctionBegin; 3625 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3626 PetscAssertPointer(support, 3); 3627 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3628 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3629 PetscFunctionReturn(PETSC_SUCCESS); 3630 } 3631 3632 /*@ 3633 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3634 3635 Not Collective 3636 3637 Input Parameters: 3638 + dm - The `DMPLEX` 3639 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3640 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3641 3642 Level: beginner 3643 3644 Note: 3645 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3646 3647 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3648 @*/ 3649 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3650 { 3651 DM_Plex *mesh = (DM_Plex *)dm->data; 3652 PetscInt pStart, pEnd; 3653 PetscInt dof, off, c; 3654 3655 PetscFunctionBegin; 3656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3657 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3658 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3659 if (dof) PetscAssertPointer(support, 3); 3660 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3661 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); 3662 for (c = 0; c < dof; ++c) { 3663 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); 3664 mesh->supports[off + c] = support[c]; 3665 } 3666 PetscFunctionReturn(PETSC_SUCCESS); 3667 } 3668 3669 /*@ 3670 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3671 3672 Not Collective 3673 3674 Input Parameters: 3675 + dm - The `DMPLEX` 3676 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3677 . supportPos - The local index in the cone where the point should be put 3678 - supportPoint - The mesh point to insert 3679 3680 Level: beginner 3681 3682 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3683 @*/ 3684 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3685 { 3686 DM_Plex *mesh = (DM_Plex *)dm->data; 3687 PetscInt pStart, pEnd; 3688 PetscInt dof, off; 3689 3690 PetscFunctionBegin; 3691 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3692 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3693 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3694 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3695 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); 3696 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); 3697 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); 3698 mesh->supports[off + supportPos] = supportPoint; 3699 PetscFunctionReturn(PETSC_SUCCESS); 3700 } 3701 3702 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3703 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3704 { 3705 switch (ct) { 3706 case DM_POLYTOPE_SEGMENT: 3707 if (o == -1) return -2; 3708 break; 3709 case DM_POLYTOPE_TRIANGLE: 3710 if (o == -3) return -1; 3711 if (o == -2) return -3; 3712 if (o == -1) return -2; 3713 break; 3714 case DM_POLYTOPE_QUADRILATERAL: 3715 if (o == -4) return -2; 3716 if (o == -3) return -1; 3717 if (o == -2) return -4; 3718 if (o == -1) return -3; 3719 break; 3720 default: 3721 return o; 3722 } 3723 return o; 3724 } 3725 3726 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3727 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3728 { 3729 switch (ct) { 3730 case DM_POLYTOPE_SEGMENT: 3731 if ((o == -2) || (o == 1)) return -1; 3732 if (o == -1) return 0; 3733 break; 3734 case DM_POLYTOPE_TRIANGLE: 3735 if (o == -3) return -2; 3736 if (o == -2) return -1; 3737 if (o == -1) return -3; 3738 break; 3739 case DM_POLYTOPE_QUADRILATERAL: 3740 if (o == -4) return -2; 3741 if (o == -3) return -1; 3742 if (o == -2) return -4; 3743 if (o == -1) return -3; 3744 break; 3745 default: 3746 return o; 3747 } 3748 return o; 3749 } 3750 3751 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3752 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3753 { 3754 PetscInt pStart, pEnd, p; 3755 3756 PetscFunctionBegin; 3757 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3758 for (p = pStart; p < pEnd; ++p) { 3759 const PetscInt *cone, *ornt; 3760 PetscInt coneSize, c; 3761 3762 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3763 PetscCall(DMPlexGetCone(dm, p, &cone)); 3764 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3765 for (c = 0; c < coneSize; ++c) { 3766 DMPolytopeType ct; 3767 const PetscInt o = ornt[c]; 3768 3769 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3770 switch (ct) { 3771 case DM_POLYTOPE_SEGMENT: 3772 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3773 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3774 break; 3775 case DM_POLYTOPE_TRIANGLE: 3776 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3777 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3778 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3779 break; 3780 case DM_POLYTOPE_QUADRILATERAL: 3781 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3782 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3783 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3784 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3785 break; 3786 default: 3787 break; 3788 } 3789 } 3790 } 3791 PetscFunctionReturn(PETSC_SUCCESS); 3792 } 3793 3794 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3795 { 3796 DM_Plex *mesh = (DM_Plex *)dm->data; 3797 3798 PetscFunctionBeginHot; 3799 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3800 if (useCone) { 3801 PetscCall(DMPlexGetConeSize(dm, p, size)); 3802 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3803 } else { 3804 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3805 PetscCall(DMPlexGetSupport(dm, p, arr)); 3806 } 3807 } else { 3808 if (useCone) { 3809 const PetscSection s = mesh->coneSection; 3810 const PetscInt ps = p - s->pStart; 3811 const PetscInt off = s->atlasOff[ps]; 3812 3813 *size = s->atlasDof[ps]; 3814 *arr = mesh->cones + off; 3815 *ornt = mesh->coneOrientations + off; 3816 } else { 3817 const PetscSection s = mesh->supportSection; 3818 const PetscInt ps = p - s->pStart; 3819 const PetscInt off = s->atlasOff[ps]; 3820 3821 *size = s->atlasDof[ps]; 3822 *arr = mesh->supports + off; 3823 } 3824 } 3825 PetscFunctionReturn(PETSC_SUCCESS); 3826 } 3827 3828 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3829 { 3830 DM_Plex *mesh = (DM_Plex *)dm->data; 3831 3832 PetscFunctionBeginHot; 3833 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3834 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3835 } 3836 PetscFunctionReturn(PETSC_SUCCESS); 3837 } 3838 3839 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3840 { 3841 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3842 PetscInt *closure; 3843 const PetscInt *tmp = NULL, *tmpO = NULL; 3844 PetscInt off = 0, tmpSize, t; 3845 3846 PetscFunctionBeginHot; 3847 if (ornt) { 3848 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3849 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 3850 } 3851 if (*points) { 3852 closure = *points; 3853 } else { 3854 PetscInt maxConeSize, maxSupportSize; 3855 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3856 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3857 } 3858 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3859 if (ct == DM_POLYTOPE_UNKNOWN) { 3860 closure[off++] = p; 3861 closure[off++] = 0; 3862 for (t = 0; t < tmpSize; ++t) { 3863 closure[off++] = tmp[t]; 3864 closure[off++] = tmpO ? tmpO[t] : 0; 3865 } 3866 } else { 3867 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3868 3869 /* We assume that cells with a valid type have faces with a valid type */ 3870 closure[off++] = p; 3871 closure[off++] = ornt; 3872 for (t = 0; t < tmpSize; ++t) { 3873 DMPolytopeType ft; 3874 3875 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3876 closure[off++] = tmp[arr[t]]; 3877 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3878 } 3879 } 3880 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3881 if (numPoints) *numPoints = tmpSize + 1; 3882 if (points) *points = closure; 3883 PetscFunctionReturn(PETSC_SUCCESS); 3884 } 3885 3886 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3887 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3888 { 3889 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3890 const PetscInt *cone, *ornt; 3891 PetscInt *pts, *closure = NULL; 3892 DMPolytopeType ft; 3893 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3894 PetscInt dim, coneSize, c, d, clSize, cl; 3895 3896 PetscFunctionBeginHot; 3897 PetscCall(DMGetDimension(dm, &dim)); 3898 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3899 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3900 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3901 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3902 maxSize = PetscMax(coneSeries, supportSeries); 3903 if (*points) { 3904 pts = *points; 3905 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3906 c = 0; 3907 pts[c++] = point; 3908 pts[c++] = o; 3909 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3910 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3911 for (cl = 0; cl < clSize * 2; cl += 2) { 3912 pts[c++] = closure[cl]; 3913 pts[c++] = closure[cl + 1]; 3914 } 3915 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3916 for (cl = 0; cl < clSize * 2; cl += 2) { 3917 pts[c++] = closure[cl]; 3918 pts[c++] = closure[cl + 1]; 3919 } 3920 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3921 for (d = 2; d < coneSize; ++d) { 3922 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3923 pts[c++] = cone[arr[d * 2 + 0]]; 3924 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3925 } 3926 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3927 if (dim >= 3) { 3928 for (d = 2; d < coneSize; ++d) { 3929 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3930 const PetscInt *fcone, *fornt; 3931 PetscInt fconeSize, fc, i; 3932 3933 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3934 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3935 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3936 for (fc = 0; fc < fconeSize; ++fc) { 3937 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3938 const PetscInt co = farr[fc * 2 + 1]; 3939 3940 for (i = 0; i < c; i += 2) 3941 if (pts[i] == cp) break; 3942 if (i == c) { 3943 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3944 pts[c++] = cp; 3945 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3946 } 3947 } 3948 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3949 } 3950 } 3951 *numPoints = c / 2; 3952 *points = pts; 3953 PetscFunctionReturn(PETSC_SUCCESS); 3954 } 3955 3956 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3957 { 3958 DMPolytopeType ct; 3959 PetscInt *closure, *fifo; 3960 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3961 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3962 PetscInt depth, maxSize; 3963 3964 PetscFunctionBeginHot; 3965 PetscCall(DMPlexGetDepth(dm, &depth)); 3966 if (depth == 1) { 3967 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3968 PetscFunctionReturn(PETSC_SUCCESS); 3969 } 3970 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3971 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 3972 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3973 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3974 PetscFunctionReturn(PETSC_SUCCESS); 3975 } 3976 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3977 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3978 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3979 maxSize = PetscMax(coneSeries, supportSeries); 3980 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3981 if (*points) { 3982 closure = *points; 3983 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3984 closure[closureSize++] = p; 3985 closure[closureSize++] = ornt; 3986 fifo[fifoSize++] = p; 3987 fifo[fifoSize++] = ornt; 3988 fifo[fifoSize++] = ct; 3989 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3990 while (fifoSize - fifoStart) { 3991 const PetscInt q = fifo[fifoStart++]; 3992 const PetscInt o = fifo[fifoStart++]; 3993 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3994 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 3995 const PetscInt *tmp, *tmpO = NULL; 3996 PetscInt tmpSize, t; 3997 3998 if (PetscDefined(USE_DEBUG)) { 3999 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4000 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); 4001 } 4002 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4003 for (t = 0; t < tmpSize; ++t) { 4004 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4005 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4006 const PetscInt cp = tmp[ip]; 4007 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4008 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4009 PetscInt c; 4010 4011 /* Check for duplicate */ 4012 for (c = 0; c < closureSize; c += 2) { 4013 if (closure[c] == cp) break; 4014 } 4015 if (c == closureSize) { 4016 closure[closureSize++] = cp; 4017 closure[closureSize++] = co; 4018 fifo[fifoSize++] = cp; 4019 fifo[fifoSize++] = co; 4020 fifo[fifoSize++] = ct; 4021 } 4022 } 4023 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4024 } 4025 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4026 if (numPoints) *numPoints = closureSize / 2; 4027 if (points) *points = closure; 4028 PetscFunctionReturn(PETSC_SUCCESS); 4029 } 4030 4031 /*@C 4032 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4033 4034 Not Collective 4035 4036 Input Parameters: 4037 + dm - The `DMPLEX` 4038 . p - The mesh point 4039 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4040 4041 Input/Output Parameter: 4042 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4043 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4044 otherwise the provided array is used to hold the values 4045 4046 Output Parameter: 4047 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4048 4049 Level: beginner 4050 4051 Note: 4052 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4053 4054 Fortran Notes: 4055 `points` must be declared with 4056 .vb 4057 PetscInt, pointer :: points(:) 4058 .ve 4059 and is always allocated by the function. 4060 4061 The `numPoints` argument is not present in the Fortran binding. 4062 4063 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4064 @*/ 4065 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4066 { 4067 PetscFunctionBeginHot; 4068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4069 if (numPoints) PetscAssertPointer(numPoints, 4); 4070 if (points) PetscAssertPointer(points, 5); 4071 if (PetscDefined(USE_DEBUG)) { 4072 PetscInt pStart, pEnd; 4073 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4074 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4075 } 4076 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4077 PetscFunctionReturn(PETSC_SUCCESS); 4078 } 4079 4080 /*@C 4081 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4082 4083 Not Collective 4084 4085 Input Parameters: 4086 + dm - The `DMPLEX` 4087 . p - The mesh point 4088 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4089 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4090 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4091 4092 Level: beginner 4093 4094 Note: 4095 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4096 4097 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4098 @*/ 4099 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4100 { 4101 PetscFunctionBeginHot; 4102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4103 if (numPoints) *numPoints = 0; 4104 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4105 PetscFunctionReturn(PETSC_SUCCESS); 4106 } 4107 4108 /*@ 4109 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4110 4111 Not Collective 4112 4113 Input Parameter: 4114 . dm - The `DMPLEX` 4115 4116 Output Parameters: 4117 + maxConeSize - The maximum number of in-edges 4118 - maxSupportSize - The maximum number of out-edges 4119 4120 Level: beginner 4121 4122 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4123 @*/ 4124 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4125 { 4126 DM_Plex *mesh = (DM_Plex *)dm->data; 4127 4128 PetscFunctionBegin; 4129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4130 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4131 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4132 PetscFunctionReturn(PETSC_SUCCESS); 4133 } 4134 4135 PetscErrorCode DMSetUp_Plex(DM dm) 4136 { 4137 DM_Plex *mesh = (DM_Plex *)dm->data; 4138 PetscInt size, maxSupportSize; 4139 4140 PetscFunctionBegin; 4141 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4142 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4143 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4144 PetscCall(PetscMalloc1(size, &mesh->cones)); 4145 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4146 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4147 if (maxSupportSize) { 4148 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4149 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4150 PetscCall(PetscMalloc1(size, &mesh->supports)); 4151 } 4152 PetscFunctionReturn(PETSC_SUCCESS); 4153 } 4154 4155 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4156 { 4157 PetscFunctionBegin; 4158 if (subdm) PetscCall(DMClone(dm, subdm)); 4159 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4160 if (subdm) (*subdm)->useNatural = dm->useNatural; 4161 if (dm->useNatural && dm->sfMigration) { 4162 PetscSF sfNatural; 4163 4164 (*subdm)->sfMigration = dm->sfMigration; 4165 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4166 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4167 (*subdm)->sfNatural = sfNatural; 4168 } 4169 PetscFunctionReturn(PETSC_SUCCESS); 4170 } 4171 4172 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4173 { 4174 PetscInt i = 0; 4175 4176 PetscFunctionBegin; 4177 PetscCall(DMClone(dms[0], superdm)); 4178 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4179 (*superdm)->useNatural = PETSC_FALSE; 4180 for (i = 0; i < len; i++) { 4181 if (dms[i]->useNatural && dms[i]->sfMigration) { 4182 PetscSF sfNatural; 4183 4184 (*superdm)->sfMigration = dms[i]->sfMigration; 4185 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4186 (*superdm)->useNatural = PETSC_TRUE; 4187 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4188 (*superdm)->sfNatural = sfNatural; 4189 break; 4190 } 4191 } 4192 PetscFunctionReturn(PETSC_SUCCESS); 4193 } 4194 4195 /*@ 4196 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4197 4198 Not Collective 4199 4200 Input Parameter: 4201 . dm - The `DMPLEX` 4202 4203 Level: beginner 4204 4205 Note: 4206 This should be called after all calls to `DMPlexSetCone()` 4207 4208 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4209 @*/ 4210 PetscErrorCode DMPlexSymmetrize(DM dm) 4211 { 4212 DM_Plex *mesh = (DM_Plex *)dm->data; 4213 PetscInt *offsets; 4214 PetscInt supportSize; 4215 PetscInt pStart, pEnd, p; 4216 4217 PetscFunctionBegin; 4218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4219 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4220 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4221 /* Calculate support sizes */ 4222 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4223 for (p = pStart; p < pEnd; ++p) { 4224 PetscInt dof, off, c; 4225 4226 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4227 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4228 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4229 } 4230 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4231 /* Calculate supports */ 4232 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4233 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4234 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4235 for (p = pStart; p < pEnd; ++p) { 4236 PetscInt dof, off, c; 4237 4238 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4239 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4240 for (c = off; c < off + dof; ++c) { 4241 const PetscInt q = mesh->cones[c]; 4242 PetscInt offS; 4243 4244 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4245 4246 mesh->supports[offS + offsets[q]] = p; 4247 ++offsets[q]; 4248 } 4249 } 4250 PetscCall(PetscFree(offsets)); 4251 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4252 PetscFunctionReturn(PETSC_SUCCESS); 4253 } 4254 4255 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4256 { 4257 IS stratumIS; 4258 4259 PetscFunctionBegin; 4260 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4261 if (PetscDefined(USE_DEBUG)) { 4262 PetscInt qStart, qEnd, numLevels, level; 4263 PetscBool overlap = PETSC_FALSE; 4264 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4265 for (level = 0; level < numLevels; level++) { 4266 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4267 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4268 overlap = PETSC_TRUE; 4269 break; 4270 } 4271 } 4272 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); 4273 } 4274 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4275 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4276 PetscCall(ISDestroy(&stratumIS)); 4277 PetscFunctionReturn(PETSC_SUCCESS); 4278 } 4279 4280 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4281 { 4282 PetscInt *pMin, *pMax; 4283 PetscInt pStart, pEnd; 4284 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4285 4286 PetscFunctionBegin; 4287 { 4288 DMLabel label2; 4289 4290 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4291 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4292 } 4293 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4294 for (PetscInt p = pStart; p < pEnd; ++p) { 4295 DMPolytopeType ct; 4296 4297 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4298 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4299 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4300 } 4301 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4302 for (PetscInt d = dmin; d <= dmax; ++d) { 4303 pMin[d] = PETSC_INT_MAX; 4304 pMax[d] = PETSC_INT_MIN; 4305 } 4306 for (PetscInt p = pStart; p < pEnd; ++p) { 4307 DMPolytopeType ct; 4308 PetscInt d; 4309 4310 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4311 d = DMPolytopeTypeGetDim(ct); 4312 pMin[d] = PetscMin(p, pMin[d]); 4313 pMax[d] = PetscMax(p, pMax[d]); 4314 } 4315 for (PetscInt d = dmin; d <= dmax; ++d) { 4316 if (pMin[d] > pMax[d]) continue; 4317 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4318 } 4319 PetscCall(PetscFree2(pMin, pMax)); 4320 PetscFunctionReturn(PETSC_SUCCESS); 4321 } 4322 4323 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4324 { 4325 PetscInt pStart, pEnd; 4326 PetscInt numRoots = 0, numLeaves = 0; 4327 4328 PetscFunctionBegin; 4329 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4330 { 4331 /* Initialize roots and count leaves */ 4332 PetscInt sMin = PETSC_INT_MAX; 4333 PetscInt sMax = PETSC_INT_MIN; 4334 PetscInt coneSize, supportSize; 4335 4336 for (PetscInt p = pStart; p < pEnd; ++p) { 4337 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4338 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4339 if (!coneSize && supportSize) { 4340 sMin = PetscMin(p, sMin); 4341 sMax = PetscMax(p, sMax); 4342 ++numRoots; 4343 } else if (!supportSize && coneSize) { 4344 ++numLeaves; 4345 } else if (!supportSize && !coneSize) { 4346 /* Isolated points */ 4347 sMin = PetscMin(p, sMin); 4348 sMax = PetscMax(p, sMax); 4349 } 4350 } 4351 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4352 } 4353 4354 if (numRoots + numLeaves == (pEnd - pStart)) { 4355 PetscInt sMin = PETSC_INT_MAX; 4356 PetscInt sMax = PETSC_INT_MIN; 4357 PetscInt coneSize, supportSize; 4358 4359 for (PetscInt p = pStart; p < pEnd; ++p) { 4360 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4361 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4362 if (!supportSize && coneSize) { 4363 sMin = PetscMin(p, sMin); 4364 sMax = PetscMax(p, sMax); 4365 } 4366 } 4367 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4368 } else { 4369 PetscInt level = 0; 4370 PetscInt qStart, qEnd; 4371 4372 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4373 while (qEnd > qStart) { 4374 PetscInt sMin = PETSC_INT_MAX; 4375 PetscInt sMax = PETSC_INT_MIN; 4376 4377 for (PetscInt q = qStart; q < qEnd; ++q) { 4378 const PetscInt *support; 4379 PetscInt supportSize; 4380 4381 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4382 PetscCall(DMPlexGetSupport(dm, q, &support)); 4383 for (PetscInt s = 0; s < supportSize; ++s) { 4384 sMin = PetscMin(support[s], sMin); 4385 sMax = PetscMax(support[s], sMax); 4386 } 4387 } 4388 PetscCall(DMLabelGetNumValues(label, &level)); 4389 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4390 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4391 } 4392 } 4393 PetscFunctionReturn(PETSC_SUCCESS); 4394 } 4395 4396 /*@ 4397 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4398 4399 Collective 4400 4401 Input Parameter: 4402 . dm - The `DMPLEX` 4403 4404 Level: beginner 4405 4406 Notes: 4407 The strata group all points of the same grade, and this function calculates the strata. This 4408 grade can be seen as the height (or depth) of the point in the DAG. 4409 4410 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4411 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4412 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4413 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4414 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4415 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4416 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4417 4418 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4419 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4420 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 4421 to interpolate only that one (e0), so that 4422 .vb 4423 cone(c0) = {e0, v2} 4424 cone(e0) = {v0, v1} 4425 .ve 4426 If `DMPlexStratify()` is run on this mesh, it will give depths 4427 .vb 4428 depth 0 = {v0, v1, v2} 4429 depth 1 = {e0, c0} 4430 .ve 4431 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4432 4433 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4434 4435 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4436 @*/ 4437 PetscErrorCode DMPlexStratify(DM dm) 4438 { 4439 DM_Plex *mesh = (DM_Plex *)dm->data; 4440 DMLabel label; 4441 PetscBool flg = PETSC_FALSE; 4442 4443 PetscFunctionBegin; 4444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4445 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4446 4447 // Create depth label 4448 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4449 PetscCall(DMCreateLabel(dm, "depth")); 4450 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4451 4452 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4453 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4454 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4455 4456 { /* just in case there is an empty process */ 4457 PetscInt numValues, maxValues = 0, v; 4458 4459 PetscCall(DMLabelGetNumValues(label, &numValues)); 4460 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4461 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4462 } 4463 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4464 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4465 PetscFunctionReturn(PETSC_SUCCESS); 4466 } 4467 4468 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4469 { 4470 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4471 PetscInt dim, depth, pheight, coneSize; 4472 4473 PetscFunctionBeginHot; 4474 PetscCall(DMGetDimension(dm, &dim)); 4475 PetscCall(DMPlexGetDepth(dm, &depth)); 4476 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4477 pheight = depth - pdepth; 4478 if (depth <= 1) { 4479 switch (pdepth) { 4480 case 0: 4481 ct = DM_POLYTOPE_POINT; 4482 break; 4483 case 1: 4484 switch (coneSize) { 4485 case 2: 4486 ct = DM_POLYTOPE_SEGMENT; 4487 break; 4488 case 3: 4489 ct = DM_POLYTOPE_TRIANGLE; 4490 break; 4491 case 4: 4492 switch (dim) { 4493 case 2: 4494 ct = DM_POLYTOPE_QUADRILATERAL; 4495 break; 4496 case 3: 4497 ct = DM_POLYTOPE_TETRAHEDRON; 4498 break; 4499 default: 4500 break; 4501 } 4502 break; 4503 case 5: 4504 ct = DM_POLYTOPE_PYRAMID; 4505 break; 4506 case 6: 4507 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4508 break; 4509 case 8: 4510 ct = DM_POLYTOPE_HEXAHEDRON; 4511 break; 4512 default: 4513 break; 4514 } 4515 } 4516 } else { 4517 if (pdepth == 0) { 4518 ct = DM_POLYTOPE_POINT; 4519 } else if (pheight == 0) { 4520 switch (dim) { 4521 case 1: 4522 switch (coneSize) { 4523 case 2: 4524 ct = DM_POLYTOPE_SEGMENT; 4525 break; 4526 default: 4527 break; 4528 } 4529 break; 4530 case 2: 4531 switch (coneSize) { 4532 case 3: 4533 ct = DM_POLYTOPE_TRIANGLE; 4534 break; 4535 case 4: 4536 ct = DM_POLYTOPE_QUADRILATERAL; 4537 break; 4538 default: 4539 break; 4540 } 4541 break; 4542 case 3: 4543 switch (coneSize) { 4544 case 4: 4545 ct = DM_POLYTOPE_TETRAHEDRON; 4546 break; 4547 case 5: { 4548 const PetscInt *cone; 4549 PetscInt faceConeSize; 4550 4551 PetscCall(DMPlexGetCone(dm, p, &cone)); 4552 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4553 switch (faceConeSize) { 4554 case 3: 4555 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4556 break; 4557 case 4: 4558 ct = DM_POLYTOPE_PYRAMID; 4559 break; 4560 } 4561 } break; 4562 case 6: 4563 ct = DM_POLYTOPE_HEXAHEDRON; 4564 break; 4565 default: 4566 break; 4567 } 4568 break; 4569 default: 4570 break; 4571 } 4572 } else if (pheight > 0) { 4573 switch (coneSize) { 4574 case 2: 4575 ct = DM_POLYTOPE_SEGMENT; 4576 break; 4577 case 3: 4578 ct = DM_POLYTOPE_TRIANGLE; 4579 break; 4580 case 4: 4581 ct = DM_POLYTOPE_QUADRILATERAL; 4582 break; 4583 default: 4584 break; 4585 } 4586 } 4587 } 4588 *pt = ct; 4589 PetscFunctionReturn(PETSC_SUCCESS); 4590 } 4591 4592 /*@ 4593 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4594 4595 Collective 4596 4597 Input Parameter: 4598 . dm - The `DMPLEX` 4599 4600 Level: developer 4601 4602 Note: 4603 This function is normally called automatically when a cell type is requested. It creates an 4604 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4605 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4606 4607 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4608 4609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4610 @*/ 4611 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4612 { 4613 DM_Plex *mesh; 4614 DMLabel ctLabel; 4615 PetscInt pStart, pEnd, p; 4616 4617 PetscFunctionBegin; 4618 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4619 mesh = (DM_Plex *)dm->data; 4620 PetscCall(DMCreateLabel(dm, "celltype")); 4621 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4622 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4623 PetscCall(PetscFree(mesh->cellTypes)); 4624 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4625 for (p = pStart; p < pEnd; ++p) { 4626 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4627 PetscInt pdepth; 4628 4629 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4630 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4631 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4632 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4633 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4634 } 4635 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4636 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4637 PetscFunctionReturn(PETSC_SUCCESS); 4638 } 4639 4640 /*@C 4641 DMPlexGetJoin - Get an array for the join of the set of points 4642 4643 Not Collective 4644 4645 Input Parameters: 4646 + dm - The `DMPLEX` object 4647 . numPoints - The number of input points for the join 4648 - points - The input points 4649 4650 Output Parameters: 4651 + numCoveredPoints - The number of points in the join 4652 - coveredPoints - The points in the join 4653 4654 Level: intermediate 4655 4656 Note: 4657 Currently, this is restricted to a single level join 4658 4659 Fortran Notes: 4660 `converedPoints` must be declared with 4661 .vb 4662 PetscInt, pointer :: coveredPints(:) 4663 .ve 4664 4665 The `numCoveredPoints` argument is not present in the Fortran binding. 4666 4667 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4668 @*/ 4669 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4670 { 4671 DM_Plex *mesh = (DM_Plex *)dm->data; 4672 PetscInt *join[2]; 4673 PetscInt joinSize, i = 0; 4674 PetscInt dof, off, p, c, m; 4675 PetscInt maxSupportSize; 4676 4677 PetscFunctionBegin; 4678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4679 PetscAssertPointer(points, 3); 4680 PetscAssertPointer(numCoveredPoints, 4); 4681 PetscAssertPointer(coveredPoints, 5); 4682 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4683 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4684 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4685 /* Copy in support of first point */ 4686 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4687 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4688 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4689 /* Check each successive support */ 4690 for (p = 1; p < numPoints; ++p) { 4691 PetscInt newJoinSize = 0; 4692 4693 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4694 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4695 for (c = 0; c < dof; ++c) { 4696 const PetscInt point = mesh->supports[off + c]; 4697 4698 for (m = 0; m < joinSize; ++m) { 4699 if (point == join[i][m]) { 4700 join[1 - i][newJoinSize++] = point; 4701 break; 4702 } 4703 } 4704 } 4705 joinSize = newJoinSize; 4706 i = 1 - i; 4707 } 4708 *numCoveredPoints = joinSize; 4709 *coveredPoints = join[i]; 4710 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4711 PetscFunctionReturn(PETSC_SUCCESS); 4712 } 4713 4714 /*@C 4715 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4716 4717 Not Collective 4718 4719 Input Parameters: 4720 + dm - The `DMPLEX` object 4721 . numPoints - The number of input points for the join 4722 - points - The input points 4723 4724 Output Parameters: 4725 + numCoveredPoints - The number of points in the join 4726 - coveredPoints - The points in the join 4727 4728 Level: intermediate 4729 4730 Fortran Notes: 4731 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4732 4733 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4734 @*/ 4735 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4736 { 4737 PetscFunctionBegin; 4738 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4739 if (points) PetscAssertPointer(points, 3); 4740 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4741 PetscAssertPointer(coveredPoints, 5); 4742 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4743 if (numCoveredPoints) *numCoveredPoints = 0; 4744 PetscFunctionReturn(PETSC_SUCCESS); 4745 } 4746 4747 /*@C 4748 DMPlexGetFullJoin - Get an array for the join of the set of points 4749 4750 Not Collective 4751 4752 Input Parameters: 4753 + dm - The `DMPLEX` object 4754 . numPoints - The number of input points for the join 4755 - points - The input points, its length is `numPoints` 4756 4757 Output Parameters: 4758 + numCoveredPoints - The number of points in the join 4759 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4760 4761 Level: intermediate 4762 4763 Fortran Notes: 4764 `points` and `converedPoints` must be declared with 4765 .vb 4766 PetscInt, pointer :: points(:) 4767 PetscInt, pointer :: coveredPints(:) 4768 .ve 4769 4770 The `numCoveredPoints` argument is not present in the Fortran binding. 4771 4772 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4773 @*/ 4774 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4775 { 4776 PetscInt *offsets, **closures; 4777 PetscInt *join[2]; 4778 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4779 PetscInt p, d, c, m, ms; 4780 4781 PetscFunctionBegin; 4782 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4783 PetscAssertPointer(points, 3); 4784 PetscAssertPointer(numCoveredPoints, 4); 4785 PetscAssertPointer(coveredPoints, 5); 4786 4787 PetscCall(DMPlexGetDepth(dm, &depth)); 4788 PetscCall(PetscCalloc1(numPoints, &closures)); 4789 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4790 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4791 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4792 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4793 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4794 4795 for (p = 0; p < numPoints; ++p) { 4796 PetscInt closureSize; 4797 4798 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4799 4800 offsets[p * (depth + 2) + 0] = 0; 4801 for (d = 0; d < depth + 1; ++d) { 4802 PetscInt pStart, pEnd, i; 4803 4804 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4805 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4806 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4807 offsets[p * (depth + 2) + d + 1] = i; 4808 break; 4809 } 4810 } 4811 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4812 } 4813 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); 4814 } 4815 for (d = 0; d < depth + 1; ++d) { 4816 PetscInt dof; 4817 4818 /* Copy in support of first point */ 4819 dof = offsets[d + 1] - offsets[d]; 4820 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4821 /* Check each successive cone */ 4822 for (p = 1; p < numPoints && joinSize; ++p) { 4823 PetscInt newJoinSize = 0; 4824 4825 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4826 for (c = 0; c < dof; ++c) { 4827 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4828 4829 for (m = 0; m < joinSize; ++m) { 4830 if (point == join[i][m]) { 4831 join[1 - i][newJoinSize++] = point; 4832 break; 4833 } 4834 } 4835 } 4836 joinSize = newJoinSize; 4837 i = 1 - i; 4838 } 4839 if (joinSize) break; 4840 } 4841 *numCoveredPoints = joinSize; 4842 *coveredPoints = join[i]; 4843 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4844 PetscCall(PetscFree(closures)); 4845 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4846 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4847 PetscFunctionReturn(PETSC_SUCCESS); 4848 } 4849 4850 /*@C 4851 DMPlexGetMeet - Get an array for the meet of the set of points 4852 4853 Not Collective 4854 4855 Input Parameters: 4856 + dm - The `DMPLEX` object 4857 . numPoints - The number of input points for the meet 4858 - points - The input points, of length `numPoints` 4859 4860 Output Parameters: 4861 + numCoveringPoints - The number of points in the meet 4862 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4863 4864 Level: intermediate 4865 4866 Note: 4867 Currently, this is restricted to a single level meet 4868 4869 Fortran Notes: 4870 `coveringPoints` must be declared with 4871 .vb 4872 PetscInt, pointer :: coveringPoints(:) 4873 .ve 4874 4875 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4876 4877 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4878 @*/ 4879 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4880 { 4881 DM_Plex *mesh = (DM_Plex *)dm->data; 4882 PetscInt *meet[2]; 4883 PetscInt meetSize, i = 0; 4884 PetscInt dof, off, p, c, m; 4885 PetscInt maxConeSize; 4886 4887 PetscFunctionBegin; 4888 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4889 PetscAssertPointer(points, 3); 4890 PetscAssertPointer(numCoveringPoints, 4); 4891 PetscAssertPointer(coveringPoints, 5); 4892 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4893 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4894 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4895 /* Copy in cone of first point */ 4896 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4897 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4898 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4899 /* Check each successive cone */ 4900 for (p = 1; p < numPoints; ++p) { 4901 PetscInt newMeetSize = 0; 4902 4903 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4904 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4905 for (c = 0; c < dof; ++c) { 4906 const PetscInt point = mesh->cones[off + c]; 4907 4908 for (m = 0; m < meetSize; ++m) { 4909 if (point == meet[i][m]) { 4910 meet[1 - i][newMeetSize++] = point; 4911 break; 4912 } 4913 } 4914 } 4915 meetSize = newMeetSize; 4916 i = 1 - i; 4917 } 4918 *numCoveringPoints = meetSize; 4919 *coveringPoints = meet[i]; 4920 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4921 PetscFunctionReturn(PETSC_SUCCESS); 4922 } 4923 4924 /*@C 4925 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 4926 4927 Not Collective 4928 4929 Input Parameters: 4930 + dm - The `DMPLEX` object 4931 . numPoints - The number of input points for the meet 4932 - points - The input points 4933 4934 Output Parameters: 4935 + numCoveredPoints - The number of points in the meet 4936 - coveredPoints - The points in the meet 4937 4938 Level: intermediate 4939 4940 Fortran Notes: 4941 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4942 4943 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4944 @*/ 4945 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4946 { 4947 PetscFunctionBegin; 4948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4949 if (points) PetscAssertPointer(points, 3); 4950 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4951 PetscAssertPointer(coveredPoints, 5); 4952 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4953 if (numCoveredPoints) *numCoveredPoints = 0; 4954 PetscFunctionReturn(PETSC_SUCCESS); 4955 } 4956 4957 /*@C 4958 DMPlexGetFullMeet - Get an array for the meet of the set of points 4959 4960 Not Collective 4961 4962 Input Parameters: 4963 + dm - The `DMPLEX` object 4964 . numPoints - The number of input points for the meet 4965 - points - The input points, of length `numPoints` 4966 4967 Output Parameters: 4968 + numCoveredPoints - The number of points in the meet 4969 - coveredPoints - The points in the meet, of length `numCoveredPoints` 4970 4971 Level: intermediate 4972 4973 Fortran Notes: 4974 `points` and `coveredPoints` must be declared with 4975 .vb 4976 PetscInt, pointer :: points(:) 4977 PetscInt, pointer :: coveredPoints(:) 4978 .ve 4979 4980 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4981 4982 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4983 @*/ 4984 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4985 { 4986 PetscInt *offsets, **closures; 4987 PetscInt *meet[2]; 4988 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4989 PetscInt p, h, c, m, mc; 4990 4991 PetscFunctionBegin; 4992 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4993 PetscAssertPointer(points, 3); 4994 PetscAssertPointer(numCoveredPoints, 4); 4995 PetscAssertPointer(coveredPoints, 5); 4996 4997 PetscCall(DMPlexGetDepth(dm, &height)); 4998 PetscCall(PetscMalloc1(numPoints, &closures)); 4999 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5000 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5001 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5002 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5003 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5004 5005 for (p = 0; p < numPoints; ++p) { 5006 PetscInt closureSize; 5007 5008 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5009 5010 offsets[p * (height + 2) + 0] = 0; 5011 for (h = 0; h < height + 1; ++h) { 5012 PetscInt pStart, pEnd, i; 5013 5014 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5015 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5016 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5017 offsets[p * (height + 2) + h + 1] = i; 5018 break; 5019 } 5020 } 5021 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5022 } 5023 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); 5024 } 5025 for (h = 0; h < height + 1; ++h) { 5026 PetscInt dof; 5027 5028 /* Copy in cone of first point */ 5029 dof = offsets[h + 1] - offsets[h]; 5030 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5031 /* Check each successive cone */ 5032 for (p = 1; p < numPoints && meetSize; ++p) { 5033 PetscInt newMeetSize = 0; 5034 5035 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5036 for (c = 0; c < dof; ++c) { 5037 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5038 5039 for (m = 0; m < meetSize; ++m) { 5040 if (point == meet[i][m]) { 5041 meet[1 - i][newMeetSize++] = point; 5042 break; 5043 } 5044 } 5045 } 5046 meetSize = newMeetSize; 5047 i = 1 - i; 5048 } 5049 if (meetSize) break; 5050 } 5051 *numCoveredPoints = meetSize; 5052 *coveredPoints = meet[i]; 5053 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5054 PetscCall(PetscFree(closures)); 5055 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5056 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5057 PetscFunctionReturn(PETSC_SUCCESS); 5058 } 5059 5060 /*@ 5061 DMPlexEqual - Determine if two `DM` have the same topology 5062 5063 Not Collective 5064 5065 Input Parameters: 5066 + dmA - A `DMPLEX` object 5067 - dmB - A `DMPLEX` object 5068 5069 Output Parameter: 5070 . equal - `PETSC_TRUE` if the topologies are identical 5071 5072 Level: intermediate 5073 5074 Note: 5075 We are not solving graph isomorphism, so we do not permute. 5076 5077 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5078 @*/ 5079 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5080 { 5081 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5082 5083 PetscFunctionBegin; 5084 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5085 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5086 PetscAssertPointer(equal, 3); 5087 5088 *equal = PETSC_FALSE; 5089 PetscCall(DMPlexGetDepth(dmA, &depth)); 5090 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5091 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5092 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5093 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5094 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5095 for (p = pStart; p < pEnd; ++p) { 5096 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5097 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5098 5099 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5100 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5101 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5102 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5103 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5104 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5105 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5106 for (c = 0; c < coneSize; ++c) { 5107 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5108 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5109 } 5110 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5111 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5112 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5113 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5114 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5115 for (s = 0; s < supportSize; ++s) { 5116 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5117 } 5118 } 5119 *equal = PETSC_TRUE; 5120 PetscFunctionReturn(PETSC_SUCCESS); 5121 } 5122 5123 /*@ 5124 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5125 5126 Not Collective 5127 5128 Input Parameters: 5129 + dm - The `DMPLEX` 5130 . cellDim - The cell dimension 5131 - numCorners - The number of vertices on a cell 5132 5133 Output Parameter: 5134 . numFaceVertices - The number of vertices on a face 5135 5136 Level: developer 5137 5138 Note: 5139 Of course this can only work for a restricted set of symmetric shapes 5140 5141 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5142 @*/ 5143 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5144 { 5145 MPI_Comm comm; 5146 5147 PetscFunctionBegin; 5148 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5149 PetscAssertPointer(numFaceVertices, 4); 5150 switch (cellDim) { 5151 case 0: 5152 *numFaceVertices = 0; 5153 break; 5154 case 1: 5155 *numFaceVertices = 1; 5156 break; 5157 case 2: 5158 switch (numCorners) { 5159 case 3: /* triangle */ 5160 *numFaceVertices = 2; /* Edge has 2 vertices */ 5161 break; 5162 case 4: /* quadrilateral */ 5163 *numFaceVertices = 2; /* Edge has 2 vertices */ 5164 break; 5165 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5166 *numFaceVertices = 3; /* Edge has 3 vertices */ 5167 break; 5168 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5169 *numFaceVertices = 3; /* Edge has 3 vertices */ 5170 break; 5171 default: 5172 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5173 } 5174 break; 5175 case 3: 5176 switch (numCorners) { 5177 case 4: /* tetradehdron */ 5178 *numFaceVertices = 3; /* Face has 3 vertices */ 5179 break; 5180 case 6: /* tet cohesive cells */ 5181 *numFaceVertices = 4; /* Face has 4 vertices */ 5182 break; 5183 case 8: /* hexahedron */ 5184 *numFaceVertices = 4; /* Face has 4 vertices */ 5185 break; 5186 case 9: /* tet cohesive Lagrange cells */ 5187 *numFaceVertices = 6; /* Face has 6 vertices */ 5188 break; 5189 case 10: /* quadratic tetrahedron */ 5190 *numFaceVertices = 6; /* Face has 6 vertices */ 5191 break; 5192 case 12: /* hex cohesive Lagrange cells */ 5193 *numFaceVertices = 6; /* Face has 6 vertices */ 5194 break; 5195 case 18: /* quadratic tet cohesive Lagrange cells */ 5196 *numFaceVertices = 6; /* Face has 6 vertices */ 5197 break; 5198 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5199 *numFaceVertices = 9; /* Face has 9 vertices */ 5200 break; 5201 default: 5202 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5203 } 5204 break; 5205 default: 5206 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5207 } 5208 PetscFunctionReturn(PETSC_SUCCESS); 5209 } 5210 5211 /*@ 5212 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5213 5214 Not Collective 5215 5216 Input Parameter: 5217 . dm - The `DMPLEX` object 5218 5219 Output Parameter: 5220 . depthLabel - The `DMLabel` recording point depth 5221 5222 Level: developer 5223 5224 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5225 @*/ 5226 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5227 { 5228 PetscFunctionBegin; 5229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5230 PetscAssertPointer(depthLabel, 2); 5231 *depthLabel = dm->depthLabel; 5232 PetscFunctionReturn(PETSC_SUCCESS); 5233 } 5234 5235 /*@ 5236 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5237 5238 Not Collective 5239 5240 Input Parameter: 5241 . dm - The `DMPLEX` object 5242 5243 Output Parameter: 5244 . depth - The number of strata (breadth first levels) in the DAG 5245 5246 Level: developer 5247 5248 Notes: 5249 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5250 5251 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5252 5253 An empty mesh gives -1. 5254 5255 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5256 @*/ 5257 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5258 { 5259 DM_Plex *mesh = (DM_Plex *)dm->data; 5260 DMLabel label; 5261 PetscInt d = -1; 5262 5263 PetscFunctionBegin; 5264 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5265 PetscAssertPointer(depth, 2); 5266 if (mesh->tr) { 5267 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5268 } else { 5269 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5270 // Allow missing depths 5271 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5272 *depth = d; 5273 } 5274 PetscFunctionReturn(PETSC_SUCCESS); 5275 } 5276 5277 /*@ 5278 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5279 5280 Not Collective 5281 5282 Input Parameters: 5283 + dm - The `DMPLEX` object 5284 - depth - The requested depth 5285 5286 Output Parameters: 5287 + start - The first point at this `depth` 5288 - end - One beyond the last point at this `depth` 5289 5290 Level: developer 5291 5292 Notes: 5293 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5294 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5295 higher dimension, e.g., "edges". 5296 5297 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5298 @*/ 5299 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5300 { 5301 DM_Plex *mesh = (DM_Plex *)dm->data; 5302 DMLabel label; 5303 PetscInt pStart, pEnd; 5304 5305 PetscFunctionBegin; 5306 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5307 if (start) { 5308 PetscAssertPointer(start, 3); 5309 *start = 0; 5310 } 5311 if (end) { 5312 PetscAssertPointer(end, 4); 5313 *end = 0; 5314 } 5315 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5316 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5317 if (depth < 0) { 5318 if (start) *start = pStart; 5319 if (end) *end = pEnd; 5320 PetscFunctionReturn(PETSC_SUCCESS); 5321 } 5322 if (mesh->tr) { 5323 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5324 } else { 5325 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5326 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5327 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5328 } 5329 PetscFunctionReturn(PETSC_SUCCESS); 5330 } 5331 5332 /*@ 5333 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5334 5335 Not Collective 5336 5337 Input Parameters: 5338 + dm - The `DMPLEX` object 5339 - height - The requested height 5340 5341 Output Parameters: 5342 + start - The first point at this `height` 5343 - end - One beyond the last point at this `height` 5344 5345 Level: developer 5346 5347 Notes: 5348 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5349 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5350 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5351 5352 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5353 @*/ 5354 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5355 { 5356 DMLabel label; 5357 PetscInt depth, pStart, pEnd; 5358 5359 PetscFunctionBegin; 5360 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5361 if (start) { 5362 PetscAssertPointer(start, 3); 5363 *start = 0; 5364 } 5365 if (end) { 5366 PetscAssertPointer(end, 4); 5367 *end = 0; 5368 } 5369 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5370 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5371 if (height < 0) { 5372 if (start) *start = pStart; 5373 if (end) *end = pEnd; 5374 PetscFunctionReturn(PETSC_SUCCESS); 5375 } 5376 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5377 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5378 else PetscCall(DMGetDimension(dm, &depth)); 5379 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5380 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5381 PetscFunctionReturn(PETSC_SUCCESS); 5382 } 5383 5384 /*@ 5385 DMPlexGetPointDepth - Get the `depth` of a given point 5386 5387 Not Collective 5388 5389 Input Parameters: 5390 + dm - The `DMPLEX` object 5391 - point - The point 5392 5393 Output Parameter: 5394 . depth - The depth of the `point` 5395 5396 Level: intermediate 5397 5398 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5399 @*/ 5400 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5401 { 5402 PetscFunctionBegin; 5403 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5404 PetscAssertPointer(depth, 3); 5405 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5406 PetscFunctionReturn(PETSC_SUCCESS); 5407 } 5408 5409 /*@ 5410 DMPlexGetPointHeight - Get the `height` of a given point 5411 5412 Not Collective 5413 5414 Input Parameters: 5415 + dm - The `DMPLEX` object 5416 - point - The point 5417 5418 Output Parameter: 5419 . height - The height of the `point` 5420 5421 Level: intermediate 5422 5423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5424 @*/ 5425 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5426 { 5427 PetscInt n, pDepth; 5428 5429 PetscFunctionBegin; 5430 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5431 PetscAssertPointer(height, 3); 5432 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5433 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5434 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5435 PetscFunctionReturn(PETSC_SUCCESS); 5436 } 5437 5438 /*@ 5439 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5440 5441 Not Collective 5442 5443 Input Parameter: 5444 . dm - The `DMPLEX` object 5445 5446 Output Parameter: 5447 . celltypeLabel - The `DMLabel` recording cell polytope type 5448 5449 Level: developer 5450 5451 Note: 5452 This function will trigger automatica computation of cell types. This can be disabled by calling 5453 `DMCreateLabel`(dm, "celltype") beforehand. 5454 5455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5456 @*/ 5457 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5458 { 5459 PetscFunctionBegin; 5460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5461 PetscAssertPointer(celltypeLabel, 2); 5462 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5463 *celltypeLabel = dm->celltypeLabel; 5464 PetscFunctionReturn(PETSC_SUCCESS); 5465 } 5466 5467 /*@ 5468 DMPlexGetCellType - Get the polytope type of a given cell 5469 5470 Not Collective 5471 5472 Input Parameters: 5473 + dm - The `DMPLEX` object 5474 - cell - The cell 5475 5476 Output Parameter: 5477 . celltype - The polytope type of the cell 5478 5479 Level: intermediate 5480 5481 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5482 @*/ 5483 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5484 { 5485 DM_Plex *mesh = (DM_Plex *)dm->data; 5486 DMLabel label; 5487 PetscInt ct; 5488 5489 PetscFunctionBegin; 5490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5491 PetscAssertPointer(celltype, 3); 5492 if (mesh->tr) { 5493 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5494 } else { 5495 PetscInt pStart, pEnd; 5496 5497 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5498 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5499 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5500 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5501 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5502 for (PetscInt p = pStart; p < pEnd; p++) { 5503 PetscCall(DMLabelGetValue(label, p, &ct)); 5504 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5505 } 5506 } 5507 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5508 if (PetscDefined(USE_DEBUG)) { 5509 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5510 PetscCall(DMLabelGetValue(label, cell, &ct)); 5511 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5512 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5513 } 5514 } 5515 PetscFunctionReturn(PETSC_SUCCESS); 5516 } 5517 5518 /*@ 5519 DMPlexSetCellType - Set the polytope type of a given cell 5520 5521 Not Collective 5522 5523 Input Parameters: 5524 + dm - The `DMPLEX` object 5525 . cell - The cell 5526 - celltype - The polytope type of the cell 5527 5528 Level: advanced 5529 5530 Note: 5531 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5532 is executed. This function will override the computed type. However, if automatic classification will not succeed 5533 and a user wants to manually specify all types, the classification must be disabled by calling 5534 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5535 5536 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5537 @*/ 5538 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5539 { 5540 DM_Plex *mesh = (DM_Plex *)dm->data; 5541 DMLabel label; 5542 PetscInt pStart, pEnd; 5543 5544 PetscFunctionBegin; 5545 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5546 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5547 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5548 PetscCall(DMLabelSetValue(label, cell, celltype)); 5549 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5550 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5551 PetscFunctionReturn(PETSC_SUCCESS); 5552 } 5553 5554 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5555 { 5556 PetscSection section; 5557 PetscInt maxHeight; 5558 const char *prefix; 5559 5560 PetscFunctionBegin; 5561 PetscCall(DMClone(dm, cdm)); 5562 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5563 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5564 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5565 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5566 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5567 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5568 PetscCall(DMSetLocalSection(*cdm, section)); 5569 PetscCall(PetscSectionDestroy(§ion)); 5570 5571 PetscCall(DMSetNumFields(*cdm, 1)); 5572 PetscCall(DMCreateDS(*cdm)); 5573 (*cdm)->cloneOpts = PETSC_TRUE; 5574 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5575 PetscFunctionReturn(PETSC_SUCCESS); 5576 } 5577 5578 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5579 { 5580 Vec coordsLocal, cellCoordsLocal; 5581 DM coordsDM, cellCoordsDM; 5582 5583 PetscFunctionBegin; 5584 *field = NULL; 5585 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5586 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5587 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5588 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5589 if (coordsLocal && coordsDM) { 5590 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5591 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5592 } 5593 PetscFunctionReturn(PETSC_SUCCESS); 5594 } 5595 5596 /*@ 5597 DMPlexGetConeSection - Return a section which describes the layout of cone data 5598 5599 Not Collective 5600 5601 Input Parameter: 5602 . dm - The `DMPLEX` object 5603 5604 Output Parameter: 5605 . section - The `PetscSection` object 5606 5607 Level: developer 5608 5609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5610 @*/ 5611 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5612 { 5613 DM_Plex *mesh = (DM_Plex *)dm->data; 5614 5615 PetscFunctionBegin; 5616 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5617 if (section) *section = mesh->coneSection; 5618 PetscFunctionReturn(PETSC_SUCCESS); 5619 } 5620 5621 /*@ 5622 DMPlexGetSupportSection - Return a section which describes the layout of support data 5623 5624 Not Collective 5625 5626 Input Parameter: 5627 . dm - The `DMPLEX` object 5628 5629 Output Parameter: 5630 . section - The `PetscSection` object 5631 5632 Level: developer 5633 5634 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5635 @*/ 5636 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5637 { 5638 DM_Plex *mesh = (DM_Plex *)dm->data; 5639 5640 PetscFunctionBegin; 5641 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5642 if (section) *section = mesh->supportSection; 5643 PetscFunctionReturn(PETSC_SUCCESS); 5644 } 5645 5646 /*@C 5647 DMPlexGetCones - Return cone data 5648 5649 Not Collective 5650 5651 Input Parameter: 5652 . dm - The `DMPLEX` object 5653 5654 Output Parameter: 5655 . cones - The cone for each point 5656 5657 Level: developer 5658 5659 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5660 @*/ 5661 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5662 { 5663 DM_Plex *mesh = (DM_Plex *)dm->data; 5664 5665 PetscFunctionBegin; 5666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5667 if (cones) *cones = mesh->cones; 5668 PetscFunctionReturn(PETSC_SUCCESS); 5669 } 5670 5671 /*@C 5672 DMPlexGetConeOrientations - Return cone orientation data 5673 5674 Not Collective 5675 5676 Input Parameter: 5677 . dm - The `DMPLEX` object 5678 5679 Output Parameter: 5680 . coneOrientations - The array of cone orientations for all points 5681 5682 Level: developer 5683 5684 Notes: 5685 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5686 as returned by `DMPlexGetConeOrientation()`. 5687 5688 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5689 5690 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5691 @*/ 5692 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5693 { 5694 DM_Plex *mesh = (DM_Plex *)dm->data; 5695 5696 PetscFunctionBegin; 5697 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5698 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5699 PetscFunctionReturn(PETSC_SUCCESS); 5700 } 5701 5702 /* FEM Support */ 5703 5704 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5705 { 5706 PetscInt depth; 5707 5708 PetscFunctionBegin; 5709 PetscCall(DMPlexGetDepth(plex, &depth)); 5710 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5711 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5712 PetscFunctionReturn(PETSC_SUCCESS); 5713 } 5714 5715 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5716 { 5717 PetscInt depth; 5718 5719 PetscFunctionBegin; 5720 PetscCall(DMPlexGetDepth(plex, &depth)); 5721 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5722 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5723 PetscFunctionReturn(PETSC_SUCCESS); 5724 } 5725 5726 /* 5727 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5728 representing a line in the section. 5729 */ 5730 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5731 { 5732 PetscObject obj; 5733 PetscClassId id; 5734 PetscFE fe = NULL; 5735 5736 PetscFunctionBeginHot; 5737 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5738 PetscCall(DMGetField(dm, field, NULL, &obj)); 5739 PetscCall(PetscObjectGetClassId(obj, &id)); 5740 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5741 5742 if (!fe) { 5743 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5744 /* An order k SEM disc has k-1 dofs on an edge */ 5745 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5746 *k = *k / *Nc + 1; 5747 } else { 5748 PetscInt dual_space_size, dim; 5749 PetscDualSpace dsp; 5750 5751 PetscCall(DMGetDimension(dm, &dim)); 5752 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5753 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5754 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5755 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5756 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5757 } 5758 PetscFunctionReturn(PETSC_SUCCESS); 5759 } 5760 5761 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5762 { 5763 PetscFunctionBeginHot; 5764 if (tensor) { 5765 *dof = PetscPowInt(k + 1, dim); 5766 } else { 5767 switch (dim) { 5768 case 1: 5769 *dof = k + 1; 5770 break; 5771 case 2: 5772 *dof = ((k + 1) * (k + 2)) / 2; 5773 break; 5774 case 3: 5775 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5776 break; 5777 default: 5778 *dof = 0; 5779 } 5780 } 5781 PetscFunctionReturn(PETSC_SUCCESS); 5782 } 5783 5784 /*@ 5785 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5786 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5787 section provided (or the section of the `DM`). 5788 5789 Input Parameters: 5790 + dm - The `DM` 5791 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5792 - section - The `PetscSection` to reorder, or `NULL` for the default section 5793 5794 Example: 5795 A typical interpolated single-quad mesh might order points as 5796 .vb 5797 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5798 5799 v4 -- e6 -- v3 5800 | | 5801 e7 c0 e8 5802 | | 5803 v1 -- e5 -- v2 5804 .ve 5805 5806 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5807 dofs in the order of points, e.g., 5808 .vb 5809 c0 -> [0,1,2,3] 5810 v1 -> [4] 5811 ... 5812 e5 -> [8, 9] 5813 .ve 5814 5815 which corresponds to the dofs 5816 .vb 5817 6 10 11 7 5818 13 2 3 15 5819 12 0 1 14 5820 4 8 9 5 5821 .ve 5822 5823 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5824 .vb 5825 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5826 .ve 5827 5828 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5829 .vb 5830 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5831 .ve 5832 5833 Level: developer 5834 5835 Notes: 5836 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5837 degree of the basis. 5838 5839 This is required to run with libCEED. 5840 5841 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5842 @*/ 5843 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5844 { 5845 DMLabel label; 5846 PetscInt dim, depth = -1, eStart = -1, Nf; 5847 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5848 5849 PetscFunctionBegin; 5850 PetscCall(DMGetDimension(dm, &dim)); 5851 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5852 if (point < 0) { 5853 PetscInt sStart, sEnd; 5854 5855 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5856 point = sEnd - sStart ? sStart : point; 5857 } 5858 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5859 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5860 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5861 if (depth == 1) { 5862 eStart = point; 5863 } else if (depth == dim) { 5864 const PetscInt *cone; 5865 5866 PetscCall(DMPlexGetCone(dm, point, &cone)); 5867 if (dim == 2) eStart = cone[0]; 5868 else if (dim == 3) { 5869 const PetscInt *cone2; 5870 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5871 eStart = cone2[0]; 5872 } 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); 5873 } 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); 5874 5875 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5876 for (PetscInt d = 1; d <= dim; d++) { 5877 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5878 PetscInt *perm; 5879 5880 for (f = 0; f < Nf; ++f) { 5881 PetscInt dof; 5882 5883 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5884 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5885 if (!continuous && d < dim) continue; 5886 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5887 size += dof * Nc; 5888 } 5889 PetscCall(PetscMalloc1(size, &perm)); 5890 for (f = 0; f < Nf; ++f) { 5891 switch (d) { 5892 case 1: 5893 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5894 if (!continuous && d < dim) continue; 5895 /* 5896 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5897 We want [ vtx0; edge of length k-1; vtx1 ] 5898 */ 5899 if (continuous) { 5900 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5901 for (i = 0; i < k - 1; i++) 5902 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5903 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5904 foffset = offset; 5905 } else { 5906 PetscInt dof; 5907 5908 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5909 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5910 foffset = offset; 5911 } 5912 break; 5913 case 2: 5914 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5915 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5916 if (!continuous && d < dim) continue; 5917 /* The SEM order is 5918 5919 v_lb, {e_b}, v_rb, 5920 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5921 v_lt, reverse {e_t}, v_rt 5922 */ 5923 if (continuous) { 5924 const PetscInt of = 0; 5925 const PetscInt oeb = of + PetscSqr(k - 1); 5926 const PetscInt oer = oeb + (k - 1); 5927 const PetscInt oet = oer + (k - 1); 5928 const PetscInt oel = oet + (k - 1); 5929 const PetscInt ovlb = oel + (k - 1); 5930 const PetscInt ovrb = ovlb + 1; 5931 const PetscInt ovrt = ovrb + 1; 5932 const PetscInt ovlt = ovrt + 1; 5933 PetscInt o; 5934 5935 /* bottom */ 5936 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5937 for (o = oeb; o < oer; ++o) 5938 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5939 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5940 /* middle */ 5941 for (i = 0; i < k - 1; ++i) { 5942 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5943 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5944 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5945 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5946 } 5947 /* top */ 5948 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5949 for (o = oel - 1; o >= oet; --o) 5950 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5951 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5952 foffset = offset; 5953 } else { 5954 PetscInt dof; 5955 5956 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5957 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5958 foffset = offset; 5959 } 5960 break; 5961 case 3: 5962 /* The original hex closure is 5963 5964 {c, 5965 f_b, f_t, f_f, f_b, f_r, f_l, 5966 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5967 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5968 */ 5969 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5970 if (!continuous && d < dim) continue; 5971 /* The SEM order is 5972 Bottom Slice 5973 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5974 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5975 v_blb, {e_bb}, v_brb, 5976 5977 Middle Slice (j) 5978 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5979 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5980 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5981 5982 Top Slice 5983 v_tlf, {e_tf}, v_trf, 5984 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5985 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5986 */ 5987 if (continuous) { 5988 const PetscInt oc = 0; 5989 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5990 const PetscInt oft = ofb + PetscSqr(k - 1); 5991 const PetscInt off = oft + PetscSqr(k - 1); 5992 const PetscInt ofk = off + PetscSqr(k - 1); 5993 const PetscInt ofr = ofk + PetscSqr(k - 1); 5994 const PetscInt ofl = ofr + PetscSqr(k - 1); 5995 const PetscInt oebl = ofl + PetscSqr(k - 1); 5996 const PetscInt oebb = oebl + (k - 1); 5997 const PetscInt oebr = oebb + (k - 1); 5998 const PetscInt oebf = oebr + (k - 1); 5999 const PetscInt oetf = oebf + (k - 1); 6000 const PetscInt oetr = oetf + (k - 1); 6001 const PetscInt oetb = oetr + (k - 1); 6002 const PetscInt oetl = oetb + (k - 1); 6003 const PetscInt oerf = oetl + (k - 1); 6004 const PetscInt oelf = oerf + (k - 1); 6005 const PetscInt oelb = oelf + (k - 1); 6006 const PetscInt oerb = oelb + (k - 1); 6007 const PetscInt ovblf = oerb + (k - 1); 6008 const PetscInt ovblb = ovblf + 1; 6009 const PetscInt ovbrb = ovblb + 1; 6010 const PetscInt ovbrf = ovbrb + 1; 6011 const PetscInt ovtlf = ovbrf + 1; 6012 const PetscInt ovtrf = ovtlf + 1; 6013 const PetscInt ovtrb = ovtrf + 1; 6014 const PetscInt ovtlb = ovtrb + 1; 6015 PetscInt o, n; 6016 6017 /* Bottom Slice */ 6018 /* bottom */ 6019 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6020 for (o = oetf - 1; o >= oebf; --o) 6021 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6022 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6023 /* middle */ 6024 for (i = 0; i < k - 1; ++i) { 6025 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6026 for (n = 0; n < k - 1; ++n) { 6027 o = ofb + n * (k - 1) + i; 6028 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6029 } 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6031 } 6032 /* top */ 6033 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6034 for (o = oebb; o < oebr; ++o) 6035 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6036 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6037 6038 /* Middle Slice */ 6039 for (j = 0; j < k - 1; ++j) { 6040 /* bottom */ 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6042 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6043 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6044 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6045 /* middle */ 6046 for (i = 0; i < k - 1; ++i) { 6047 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6048 for (n = 0; n < k - 1; ++n) 6049 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6050 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6051 } 6052 /* top */ 6053 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6054 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6055 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6056 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6057 } 6058 6059 /* Top Slice */ 6060 /* bottom */ 6061 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6062 for (o = oetf; o < oetr; ++o) 6063 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6064 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6065 /* middle */ 6066 for (i = 0; i < k - 1; ++i) { 6067 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6068 for (n = 0; n < k - 1; ++n) 6069 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6070 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6071 } 6072 /* top */ 6073 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6074 for (o = oetl - 1; o >= oetb; --o) 6075 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6076 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6077 6078 foffset = offset; 6079 } else { 6080 PetscInt dof; 6081 6082 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6083 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6084 foffset = offset; 6085 } 6086 break; 6087 default: 6088 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6089 } 6090 } 6091 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6092 /* Check permutation */ 6093 { 6094 PetscInt *check; 6095 6096 PetscCall(PetscMalloc1(size, &check)); 6097 for (i = 0; i < size; ++i) { 6098 check[i] = -1; 6099 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6100 } 6101 for (i = 0; i < size; ++i) check[perm[i]] = i; 6102 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6103 PetscCall(PetscFree(check)); 6104 } 6105 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6106 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6107 PetscInt *loc_perm; 6108 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6109 for (PetscInt i = 0; i < size; i++) { 6110 loc_perm[i] = perm[i]; 6111 loc_perm[size + i] = size + perm[i]; 6112 } 6113 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6114 } 6115 } 6116 PetscFunctionReturn(PETSC_SUCCESS); 6117 } 6118 6119 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6120 { 6121 PetscDS prob; 6122 PetscInt depth, Nf, h; 6123 DMLabel label; 6124 6125 PetscFunctionBeginHot; 6126 PetscCall(DMGetDS(dm, &prob)); 6127 Nf = prob->Nf; 6128 label = dm->depthLabel; 6129 *dspace = NULL; 6130 if (field < Nf) { 6131 PetscObject disc = prob->disc[field]; 6132 6133 if (disc->classid == PETSCFE_CLASSID) { 6134 PetscDualSpace dsp; 6135 6136 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6137 PetscCall(DMLabelGetNumValues(label, &depth)); 6138 PetscCall(DMLabelGetValue(label, point, &h)); 6139 h = depth - 1 - h; 6140 if (h) { 6141 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6142 } else { 6143 *dspace = dsp; 6144 } 6145 } 6146 } 6147 PetscFunctionReturn(PETSC_SUCCESS); 6148 } 6149 6150 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6151 { 6152 PetscScalar *array; 6153 const PetscScalar *vArray; 6154 const PetscInt *cone, *coneO; 6155 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6156 6157 PetscFunctionBeginHot; 6158 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6159 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6160 PetscCall(DMPlexGetCone(dm, point, &cone)); 6161 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6162 if (!values || !*values) { 6163 if ((point >= pStart) && (point < pEnd)) { 6164 PetscInt dof; 6165 6166 PetscCall(PetscSectionGetDof(section, point, &dof)); 6167 size += dof; 6168 } 6169 for (p = 0; p < numPoints; ++p) { 6170 const PetscInt cp = cone[p]; 6171 PetscInt dof; 6172 6173 if ((cp < pStart) || (cp >= pEnd)) continue; 6174 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6175 size += dof; 6176 } 6177 if (!values) { 6178 if (csize) *csize = size; 6179 PetscFunctionReturn(PETSC_SUCCESS); 6180 } 6181 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6182 } else { 6183 array = *values; 6184 } 6185 size = 0; 6186 PetscCall(VecGetArrayRead(v, &vArray)); 6187 if ((point >= pStart) && (point < pEnd)) { 6188 PetscInt dof, off, d; 6189 const PetscScalar *varr; 6190 6191 PetscCall(PetscSectionGetDof(section, point, &dof)); 6192 PetscCall(PetscSectionGetOffset(section, point, &off)); 6193 varr = PetscSafePointerPlusOffset(vArray, off); 6194 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6195 size += dof; 6196 } 6197 for (p = 0; p < numPoints; ++p) { 6198 const PetscInt cp = cone[p]; 6199 PetscInt o = coneO[p]; 6200 PetscInt dof, off, d; 6201 const PetscScalar *varr; 6202 6203 if ((cp < pStart) || (cp >= pEnd)) continue; 6204 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6205 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6206 varr = PetscSafePointerPlusOffset(vArray, off); 6207 if (o >= 0) { 6208 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6209 } else { 6210 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6211 } 6212 size += dof; 6213 } 6214 PetscCall(VecRestoreArrayRead(v, &vArray)); 6215 if (!*values) { 6216 if (csize) *csize = size; 6217 *values = array; 6218 } else { 6219 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6220 *csize = size; 6221 } 6222 PetscFunctionReturn(PETSC_SUCCESS); 6223 } 6224 6225 /* Compress out points not in the section */ 6226 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6227 { 6228 const PetscInt np = *numPoints; 6229 PetscInt pStart, pEnd, p, q; 6230 6231 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6232 for (p = 0, q = 0; p < np; ++p) { 6233 const PetscInt r = points[p * 2]; 6234 if ((r >= pStart) && (r < pEnd)) { 6235 points[q * 2] = r; 6236 points[q * 2 + 1] = points[p * 2 + 1]; 6237 ++q; 6238 } 6239 } 6240 *numPoints = q; 6241 return PETSC_SUCCESS; 6242 } 6243 6244 /* Compressed closure does not apply closure permutation */ 6245 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6246 { 6247 const PetscInt *cla = NULL; 6248 PetscInt np, *pts = NULL; 6249 6250 PetscFunctionBeginHot; 6251 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6252 if (!ornt && *clPoints) { 6253 PetscInt dof, off; 6254 6255 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6256 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6257 PetscCall(ISGetIndices(*clPoints, &cla)); 6258 np = dof / 2; 6259 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6260 } else { 6261 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6262 PetscCall(CompressPoints_Private(section, &np, pts)); 6263 } 6264 *numPoints = np; 6265 *points = pts; 6266 *clp = cla; 6267 PetscFunctionReturn(PETSC_SUCCESS); 6268 } 6269 6270 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6271 { 6272 PetscFunctionBeginHot; 6273 if (!*clPoints) { 6274 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6275 } else { 6276 PetscCall(ISRestoreIndices(*clPoints, clp)); 6277 } 6278 *numPoints = 0; 6279 *points = NULL; 6280 *clSec = NULL; 6281 *clPoints = NULL; 6282 *clp = NULL; 6283 PetscFunctionReturn(PETSC_SUCCESS); 6284 } 6285 6286 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6287 { 6288 PetscInt offset = 0, p; 6289 const PetscInt **perms = NULL; 6290 const PetscScalar **flips = NULL; 6291 6292 PetscFunctionBeginHot; 6293 *size = 0; 6294 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6295 for (p = 0; p < numPoints; p++) { 6296 const PetscInt point = points[2 * p]; 6297 const PetscInt *perm = perms ? perms[p] : NULL; 6298 const PetscScalar *flip = flips ? flips[p] : NULL; 6299 PetscInt dof, off, d; 6300 const PetscScalar *varr; 6301 6302 PetscCall(PetscSectionGetDof(section, point, &dof)); 6303 PetscCall(PetscSectionGetOffset(section, point, &off)); 6304 varr = PetscSafePointerPlusOffset(vArray, off); 6305 if (clperm) { 6306 if (perm) { 6307 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6308 } else { 6309 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6310 } 6311 if (flip) { 6312 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6313 } 6314 } else { 6315 if (perm) { 6316 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6317 } else { 6318 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6319 } 6320 if (flip) { 6321 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6322 } 6323 } 6324 offset += dof; 6325 } 6326 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6327 *size = offset; 6328 PetscFunctionReturn(PETSC_SUCCESS); 6329 } 6330 6331 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[]) 6332 { 6333 PetscInt offset = 0, f; 6334 6335 PetscFunctionBeginHot; 6336 *size = 0; 6337 for (f = 0; f < numFields; ++f) { 6338 PetscInt p; 6339 const PetscInt **perms = NULL; 6340 const PetscScalar **flips = NULL; 6341 6342 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6343 for (p = 0; p < numPoints; p++) { 6344 const PetscInt point = points[2 * p]; 6345 PetscInt fdof, foff, b; 6346 const PetscScalar *varr; 6347 const PetscInt *perm = perms ? perms[p] : NULL; 6348 const PetscScalar *flip = flips ? flips[p] : NULL; 6349 6350 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6351 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6352 varr = &vArray[foff]; 6353 if (clperm) { 6354 if (perm) { 6355 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6356 } else { 6357 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6358 } 6359 if (flip) { 6360 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6361 } 6362 } else { 6363 if (perm) { 6364 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6365 } else { 6366 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6367 } 6368 if (flip) { 6369 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6370 } 6371 } 6372 offset += fdof; 6373 } 6374 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6375 } 6376 *size = offset; 6377 PetscFunctionReturn(PETSC_SUCCESS); 6378 } 6379 6380 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6381 { 6382 PetscSection clSection; 6383 IS clPoints; 6384 PetscInt *points = NULL; 6385 const PetscInt *clp, *perm = NULL; 6386 PetscInt depth, numFields, numPoints, asize; 6387 6388 PetscFunctionBeginHot; 6389 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6390 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6391 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6392 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6393 PetscCall(DMPlexGetDepth(dm, &depth)); 6394 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6395 if (depth == 1 && numFields < 2) { 6396 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6397 PetscFunctionReturn(PETSC_SUCCESS); 6398 } 6399 /* Get points */ 6400 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6401 /* Get sizes */ 6402 asize = 0; 6403 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6404 PetscInt dof; 6405 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6406 asize += dof; 6407 } 6408 if (values) { 6409 const PetscScalar *vArray; 6410 PetscInt size; 6411 6412 if (*values) { 6413 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); 6414 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6415 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6416 PetscCall(VecGetArrayRead(v, &vArray)); 6417 /* Get values */ 6418 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6419 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6420 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6421 /* Cleanup array */ 6422 PetscCall(VecRestoreArrayRead(v, &vArray)); 6423 } 6424 if (csize) *csize = asize; 6425 /* Cleanup points */ 6426 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6427 PetscFunctionReturn(PETSC_SUCCESS); 6428 } 6429 6430 /*@C 6431 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6432 6433 Not collective 6434 6435 Input Parameters: 6436 + dm - The `DM` 6437 . section - The section describing the layout in `v`, or `NULL` to use the default section 6438 . v - The local vector 6439 - point - The point in the `DM` 6440 6441 Input/Output Parameters: 6442 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6443 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6444 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6445 6446 Level: intermediate 6447 6448 Notes: 6449 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6450 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6451 assembly function, and a user may already have allocated storage for this operation. 6452 6453 A typical use could be 6454 .vb 6455 values = NULL; 6456 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6457 for (cl = 0; cl < clSize; ++cl) { 6458 <Compute on closure> 6459 } 6460 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6461 .ve 6462 or 6463 .vb 6464 PetscMalloc1(clMaxSize, &values); 6465 for (p = pStart; p < pEnd; ++p) { 6466 clSize = clMaxSize; 6467 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6468 for (cl = 0; cl < clSize; ++cl) { 6469 <Compute on closure> 6470 } 6471 } 6472 PetscFree(values); 6473 .ve 6474 6475 Fortran Notes: 6476 The `csize` argument is not present in the Fortran binding. 6477 6478 `values` must be declared with 6479 .vb 6480 PetscScalar,dimension(:),pointer :: values 6481 .ve 6482 and it will be allocated internally by PETSc to hold the values returned 6483 6484 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6485 @*/ 6486 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6487 { 6488 PetscFunctionBeginHot; 6489 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6490 PetscFunctionReturn(PETSC_SUCCESS); 6491 } 6492 6493 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6494 { 6495 DMLabel depthLabel; 6496 PetscSection clSection; 6497 IS clPoints; 6498 PetscScalar *array; 6499 const PetscScalar *vArray; 6500 PetscInt *points = NULL; 6501 const PetscInt *clp, *perm = NULL; 6502 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6503 6504 PetscFunctionBeginHot; 6505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6506 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6507 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6508 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6509 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6510 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6511 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6512 if (mdepth == 1 && numFields < 2) { 6513 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6514 PetscFunctionReturn(PETSC_SUCCESS); 6515 } 6516 /* Get points */ 6517 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6518 for (clsize = 0, p = 0; p < Np; p++) { 6519 PetscInt dof; 6520 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6521 clsize += dof; 6522 } 6523 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6524 /* Filter points */ 6525 for (p = 0; p < numPoints * 2; p += 2) { 6526 PetscInt dep; 6527 6528 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6529 if (dep != depth) continue; 6530 points[Np * 2 + 0] = points[p]; 6531 points[Np * 2 + 1] = points[p + 1]; 6532 ++Np; 6533 } 6534 /* Get array */ 6535 if (!values || !*values) { 6536 PetscInt asize = 0, dof; 6537 6538 for (p = 0; p < Np * 2; p += 2) { 6539 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6540 asize += dof; 6541 } 6542 if (!values) { 6543 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6544 if (csize) *csize = asize; 6545 PetscFunctionReturn(PETSC_SUCCESS); 6546 } 6547 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6548 } else { 6549 array = *values; 6550 } 6551 PetscCall(VecGetArrayRead(v, &vArray)); 6552 /* Get values */ 6553 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6554 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6555 /* Cleanup points */ 6556 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6557 /* Cleanup array */ 6558 PetscCall(VecRestoreArrayRead(v, &vArray)); 6559 if (!*values) { 6560 if (csize) *csize = size; 6561 *values = array; 6562 } else { 6563 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6564 *csize = size; 6565 } 6566 PetscFunctionReturn(PETSC_SUCCESS); 6567 } 6568 6569 /*@C 6570 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6571 6572 Not collective 6573 6574 Input Parameters: 6575 + dm - The `DM` 6576 . section - The section describing the layout in `v`, or `NULL` to use the default section 6577 . v - The local vector 6578 . point - The point in the `DM` 6579 . csize - The number of values in the closure, or `NULL` 6580 - values - The array of values 6581 6582 Level: intermediate 6583 6584 Note: 6585 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6586 6587 Fortran Note: 6588 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6589 6590 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6591 @*/ 6592 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6593 { 6594 PetscInt size = 0; 6595 6596 PetscFunctionBegin; 6597 /* Should work without recalculating size */ 6598 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6599 *values = NULL; 6600 PetscFunctionReturn(PETSC_SUCCESS); 6601 } 6602 6603 static inline void add(PetscScalar *x, PetscScalar y) 6604 { 6605 *x += y; 6606 } 6607 static inline void insert(PetscScalar *x, PetscScalar y) 6608 { 6609 *x = y; 6610 } 6611 6612 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[]) 6613 { 6614 PetscInt cdof; /* The number of constraints on this point */ 6615 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6616 PetscScalar *a; 6617 PetscInt off, cind = 0, k; 6618 6619 PetscFunctionBegin; 6620 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6621 PetscCall(PetscSectionGetOffset(section, point, &off)); 6622 a = &array[off]; 6623 if (!cdof || setBC) { 6624 if (clperm) { 6625 if (perm) { 6626 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6627 } else { 6628 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6629 } 6630 } else { 6631 if (perm) { 6632 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6633 } else { 6634 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6635 } 6636 } 6637 } else { 6638 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6639 if (clperm) { 6640 if (perm) { 6641 for (k = 0; k < dof; ++k) { 6642 if ((cind < cdof) && (k == cdofs[cind])) { 6643 ++cind; 6644 continue; 6645 } 6646 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6647 } 6648 } else { 6649 for (k = 0; k < dof; ++k) { 6650 if ((cind < cdof) && (k == cdofs[cind])) { 6651 ++cind; 6652 continue; 6653 } 6654 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6655 } 6656 } 6657 } else { 6658 if (perm) { 6659 for (k = 0; k < dof; ++k) { 6660 if ((cind < cdof) && (k == cdofs[cind])) { 6661 ++cind; 6662 continue; 6663 } 6664 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6665 } 6666 } else { 6667 for (k = 0; k < dof; ++k) { 6668 if ((cind < cdof) && (k == cdofs[cind])) { 6669 ++cind; 6670 continue; 6671 } 6672 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6673 } 6674 } 6675 } 6676 } 6677 PetscFunctionReturn(PETSC_SUCCESS); 6678 } 6679 6680 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[]) 6681 { 6682 PetscInt cdof; /* The number of constraints on this point */ 6683 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6684 PetscScalar *a; 6685 PetscInt off, cind = 0, k; 6686 6687 PetscFunctionBegin; 6688 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6689 PetscCall(PetscSectionGetOffset(section, point, &off)); 6690 a = &array[off]; 6691 if (cdof) { 6692 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6693 if (clperm) { 6694 if (perm) { 6695 for (k = 0; k < dof; ++k) { 6696 if ((cind < cdof) && (k == cdofs[cind])) { 6697 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6698 cind++; 6699 } 6700 } 6701 } else { 6702 for (k = 0; k < dof; ++k) { 6703 if ((cind < cdof) && (k == cdofs[cind])) { 6704 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6705 cind++; 6706 } 6707 } 6708 } 6709 } else { 6710 if (perm) { 6711 for (k = 0; k < dof; ++k) { 6712 if ((cind < cdof) && (k == cdofs[cind])) { 6713 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6714 cind++; 6715 } 6716 } 6717 } else { 6718 for (k = 0; k < dof; ++k) { 6719 if ((cind < cdof) && (k == cdofs[cind])) { 6720 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6721 cind++; 6722 } 6723 } 6724 } 6725 } 6726 } 6727 PetscFunctionReturn(PETSC_SUCCESS); 6728 } 6729 6730 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[]) 6731 { 6732 PetscScalar *a; 6733 PetscInt fdof, foff, fcdof, foffset = *offset; 6734 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6735 PetscInt cind = 0, b; 6736 6737 PetscFunctionBegin; 6738 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6739 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6740 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6741 a = &array[foff]; 6742 if (!fcdof || setBC) { 6743 if (clperm) { 6744 if (perm) { 6745 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6746 } else { 6747 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6748 } 6749 } else { 6750 if (perm) { 6751 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6752 } else { 6753 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6754 } 6755 } 6756 } else { 6757 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6758 if (clperm) { 6759 if (perm) { 6760 for (b = 0; b < fdof; b++) { 6761 if ((cind < fcdof) && (b == fcdofs[cind])) { 6762 ++cind; 6763 continue; 6764 } 6765 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6766 } 6767 } else { 6768 for (b = 0; b < fdof; b++) { 6769 if ((cind < fcdof) && (b == fcdofs[cind])) { 6770 ++cind; 6771 continue; 6772 } 6773 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6774 } 6775 } 6776 } else { 6777 if (perm) { 6778 for (b = 0; b < fdof; b++) { 6779 if ((cind < fcdof) && (b == fcdofs[cind])) { 6780 ++cind; 6781 continue; 6782 } 6783 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6784 } 6785 } else { 6786 for (b = 0; b < fdof; b++) { 6787 if ((cind < fcdof) && (b == fcdofs[cind])) { 6788 ++cind; 6789 continue; 6790 } 6791 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6792 } 6793 } 6794 } 6795 } 6796 *offset += fdof; 6797 PetscFunctionReturn(PETSC_SUCCESS); 6798 } 6799 6800 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[]) 6801 { 6802 PetscScalar *a; 6803 PetscInt fdof, foff, fcdof, foffset = *offset; 6804 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6805 PetscInt Nc, cind = 0, ncind = 0, b; 6806 PetscBool ncSet, fcSet; 6807 6808 PetscFunctionBegin; 6809 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6810 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6811 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6812 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6813 a = &array[foff]; 6814 if (fcdof) { 6815 /* We just override fcdof and fcdofs with Ncc and comps */ 6816 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6817 if (clperm) { 6818 if (perm) { 6819 if (comps) { 6820 for (b = 0; b < fdof; b++) { 6821 ncSet = fcSet = PETSC_FALSE; 6822 if (b % Nc == comps[ncind]) { 6823 ncind = (ncind + 1) % Ncc; 6824 ncSet = PETSC_TRUE; 6825 } 6826 if ((cind < fcdof) && (b == fcdofs[cind])) { 6827 ++cind; 6828 fcSet = PETSC_TRUE; 6829 } 6830 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6831 } 6832 } else { 6833 for (b = 0; b < fdof; b++) { 6834 if ((cind < fcdof) && (b == fcdofs[cind])) { 6835 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6836 ++cind; 6837 } 6838 } 6839 } 6840 } else { 6841 if (comps) { 6842 for (b = 0; b < fdof; b++) { 6843 ncSet = fcSet = PETSC_FALSE; 6844 if (b % Nc == comps[ncind]) { 6845 ncind = (ncind + 1) % Ncc; 6846 ncSet = PETSC_TRUE; 6847 } 6848 if ((cind < fcdof) && (b == fcdofs[cind])) { 6849 ++cind; 6850 fcSet = PETSC_TRUE; 6851 } 6852 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6853 } 6854 } else { 6855 for (b = 0; b < fdof; b++) { 6856 if ((cind < fcdof) && (b == fcdofs[cind])) { 6857 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6858 ++cind; 6859 } 6860 } 6861 } 6862 } 6863 } else { 6864 if (perm) { 6865 if (comps) { 6866 for (b = 0; b < fdof; b++) { 6867 ncSet = fcSet = PETSC_FALSE; 6868 if (b % Nc == comps[ncind]) { 6869 ncind = (ncind + 1) % Ncc; 6870 ncSet = PETSC_TRUE; 6871 } 6872 if ((cind < fcdof) && (b == fcdofs[cind])) { 6873 ++cind; 6874 fcSet = PETSC_TRUE; 6875 } 6876 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6877 } 6878 } else { 6879 for (b = 0; b < fdof; b++) { 6880 if ((cind < fcdof) && (b == fcdofs[cind])) { 6881 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6882 ++cind; 6883 } 6884 } 6885 } 6886 } else { 6887 if (comps) { 6888 for (b = 0; b < fdof; b++) { 6889 ncSet = fcSet = PETSC_FALSE; 6890 if (b % Nc == comps[ncind]) { 6891 ncind = (ncind + 1) % Ncc; 6892 ncSet = PETSC_TRUE; 6893 } 6894 if ((cind < fcdof) && (b == fcdofs[cind])) { 6895 ++cind; 6896 fcSet = PETSC_TRUE; 6897 } 6898 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6899 } 6900 } else { 6901 for (b = 0; b < fdof; b++) { 6902 if ((cind < fcdof) && (b == fcdofs[cind])) { 6903 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6904 ++cind; 6905 } 6906 } 6907 } 6908 } 6909 } 6910 } 6911 *offset += fdof; 6912 PetscFunctionReturn(PETSC_SUCCESS); 6913 } 6914 6915 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6916 { 6917 PetscScalar *array; 6918 const PetscInt *cone, *coneO; 6919 PetscInt pStart, pEnd, p, numPoints, off, dof; 6920 6921 PetscFunctionBeginHot; 6922 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6923 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6924 PetscCall(DMPlexGetCone(dm, point, &cone)); 6925 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6926 PetscCall(VecGetArray(v, &array)); 6927 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6928 const PetscInt cp = !p ? point : cone[p - 1]; 6929 const PetscInt o = !p ? 0 : coneO[p - 1]; 6930 6931 if ((cp < pStart) || (cp >= pEnd)) { 6932 dof = 0; 6933 continue; 6934 } 6935 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6936 /* ADD_VALUES */ 6937 { 6938 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6939 PetscScalar *a; 6940 PetscInt cdof, coff, cind = 0, k; 6941 6942 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6943 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6944 a = &array[coff]; 6945 if (!cdof) { 6946 if (o >= 0) { 6947 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6948 } else { 6949 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6950 } 6951 } else { 6952 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6953 if (o >= 0) { 6954 for (k = 0; k < dof; ++k) { 6955 if ((cind < cdof) && (k == cdofs[cind])) { 6956 ++cind; 6957 continue; 6958 } 6959 a[k] += values[off + k]; 6960 } 6961 } else { 6962 for (k = 0; k < dof; ++k) { 6963 if ((cind < cdof) && (k == cdofs[cind])) { 6964 ++cind; 6965 continue; 6966 } 6967 a[k] += values[off + dof - k - 1]; 6968 } 6969 } 6970 } 6971 } 6972 } 6973 PetscCall(VecRestoreArray(v, &array)); 6974 PetscFunctionReturn(PETSC_SUCCESS); 6975 } 6976 6977 /*@C 6978 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6979 6980 Not collective 6981 6982 Input Parameters: 6983 + dm - The `DM` 6984 . section - The section describing the layout in `v`, or `NULL` to use the default section 6985 . v - The local vector 6986 . point - The point in the `DM` 6987 . values - The array of values 6988 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6989 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6990 6991 Level: intermediate 6992 6993 Note: 6994 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 6995 6996 Fortran Note: 6997 `values` must be declared with 6998 .vb 6999 PetscScalar,dimension(:),pointer :: values 7000 .ve 7001 7002 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7003 @*/ 7004 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7005 { 7006 PetscSection clSection; 7007 IS clPoints; 7008 PetscScalar *array; 7009 PetscInt *points = NULL; 7010 const PetscInt *clp, *clperm = NULL; 7011 PetscInt depth, numFields, numPoints, p, clsize; 7012 7013 PetscFunctionBeginHot; 7014 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7015 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7016 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7017 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7018 PetscCall(DMPlexGetDepth(dm, &depth)); 7019 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7020 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7021 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7022 PetscFunctionReturn(PETSC_SUCCESS); 7023 } 7024 /* Get points */ 7025 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7026 for (clsize = 0, p = 0; p < numPoints; p++) { 7027 PetscInt dof; 7028 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7029 clsize += dof; 7030 } 7031 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7032 /* Get array */ 7033 PetscCall(VecGetArray(v, &array)); 7034 /* Get values */ 7035 if (numFields > 0) { 7036 PetscInt offset = 0, f; 7037 for (f = 0; f < numFields; ++f) { 7038 const PetscInt **perms = NULL; 7039 const PetscScalar **flips = NULL; 7040 7041 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7042 switch (mode) { 7043 case INSERT_VALUES: 7044 for (p = 0; p < numPoints; p++) { 7045 const PetscInt point = points[2 * p]; 7046 const PetscInt *perm = perms ? perms[p] : NULL; 7047 const PetscScalar *flip = flips ? flips[p] : NULL; 7048 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7049 } 7050 break; 7051 case INSERT_ALL_VALUES: 7052 for (p = 0; p < numPoints; p++) { 7053 const PetscInt point = points[2 * p]; 7054 const PetscInt *perm = perms ? perms[p] : NULL; 7055 const PetscScalar *flip = flips ? flips[p] : NULL; 7056 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7057 } 7058 break; 7059 case INSERT_BC_VALUES: 7060 for (p = 0; p < numPoints; p++) { 7061 const PetscInt point = points[2 * p]; 7062 const PetscInt *perm = perms ? perms[p] : NULL; 7063 const PetscScalar *flip = flips ? flips[p] : NULL; 7064 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7065 } 7066 break; 7067 case ADD_VALUES: 7068 for (p = 0; p < numPoints; p++) { 7069 const PetscInt point = points[2 * p]; 7070 const PetscInt *perm = perms ? perms[p] : NULL; 7071 const PetscScalar *flip = flips ? flips[p] : NULL; 7072 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7073 } 7074 break; 7075 case ADD_ALL_VALUES: 7076 for (p = 0; p < numPoints; p++) { 7077 const PetscInt point = points[2 * p]; 7078 const PetscInt *perm = perms ? perms[p] : NULL; 7079 const PetscScalar *flip = flips ? flips[p] : NULL; 7080 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7081 } 7082 break; 7083 case ADD_BC_VALUES: 7084 for (p = 0; p < numPoints; p++) { 7085 const PetscInt point = points[2 * p]; 7086 const PetscInt *perm = perms ? perms[p] : NULL; 7087 const PetscScalar *flip = flips ? flips[p] : NULL; 7088 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7089 } 7090 break; 7091 default: 7092 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7093 } 7094 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7095 } 7096 } else { 7097 PetscInt dof, off; 7098 const PetscInt **perms = NULL; 7099 const PetscScalar **flips = NULL; 7100 7101 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7102 switch (mode) { 7103 case INSERT_VALUES: 7104 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7105 const PetscInt point = points[2 * p]; 7106 const PetscInt *perm = perms ? perms[p] : NULL; 7107 const PetscScalar *flip = flips ? flips[p] : NULL; 7108 PetscCall(PetscSectionGetDof(section, point, &dof)); 7109 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7110 } 7111 break; 7112 case INSERT_ALL_VALUES: 7113 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7114 const PetscInt point = points[2 * p]; 7115 const PetscInt *perm = perms ? perms[p] : NULL; 7116 const PetscScalar *flip = flips ? flips[p] : NULL; 7117 PetscCall(PetscSectionGetDof(section, point, &dof)); 7118 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7119 } 7120 break; 7121 case INSERT_BC_VALUES: 7122 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7123 const PetscInt point = points[2 * p]; 7124 const PetscInt *perm = perms ? perms[p] : NULL; 7125 const PetscScalar *flip = flips ? flips[p] : NULL; 7126 PetscCall(PetscSectionGetDof(section, point, &dof)); 7127 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7128 } 7129 break; 7130 case ADD_VALUES: 7131 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7132 const PetscInt point = points[2 * p]; 7133 const PetscInt *perm = perms ? perms[p] : NULL; 7134 const PetscScalar *flip = flips ? flips[p] : NULL; 7135 PetscCall(PetscSectionGetDof(section, point, &dof)); 7136 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7137 } 7138 break; 7139 case ADD_ALL_VALUES: 7140 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7141 const PetscInt point = points[2 * p]; 7142 const PetscInt *perm = perms ? perms[p] : NULL; 7143 const PetscScalar *flip = flips ? flips[p] : NULL; 7144 PetscCall(PetscSectionGetDof(section, point, &dof)); 7145 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7146 } 7147 break; 7148 case ADD_BC_VALUES: 7149 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7150 const PetscInt point = points[2 * p]; 7151 const PetscInt *perm = perms ? perms[p] : NULL; 7152 const PetscScalar *flip = flips ? flips[p] : NULL; 7153 PetscCall(PetscSectionGetDof(section, point, &dof)); 7154 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7155 } 7156 break; 7157 default: 7158 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7159 } 7160 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7161 } 7162 /* Cleanup points */ 7163 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7164 /* Cleanup array */ 7165 PetscCall(VecRestoreArray(v, &array)); 7166 PetscFunctionReturn(PETSC_SUCCESS); 7167 } 7168 7169 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7170 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7171 { 7172 PetscFunctionBegin; 7173 *contains = PETSC_TRUE; 7174 if (label) { 7175 PetscInt fdof; 7176 7177 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7178 if (!*contains) { 7179 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7180 *offset += fdof; 7181 PetscFunctionReturn(PETSC_SUCCESS); 7182 } 7183 } 7184 PetscFunctionReturn(PETSC_SUCCESS); 7185 } 7186 7187 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7188 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) 7189 { 7190 PetscSection clSection; 7191 IS clPoints; 7192 PetscScalar *array; 7193 PetscInt *points = NULL; 7194 const PetscInt *clp; 7195 PetscInt numFields, numPoints, p; 7196 PetscInt offset = 0, f; 7197 7198 PetscFunctionBeginHot; 7199 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7200 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7201 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7202 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7203 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7204 /* Get points */ 7205 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7206 /* Get array */ 7207 PetscCall(VecGetArray(v, &array)); 7208 /* Get values */ 7209 for (f = 0; f < numFields; ++f) { 7210 const PetscInt **perms = NULL; 7211 const PetscScalar **flips = NULL; 7212 PetscBool contains; 7213 7214 if (!fieldActive[f]) { 7215 for (p = 0; p < numPoints * 2; p += 2) { 7216 PetscInt fdof; 7217 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7218 offset += fdof; 7219 } 7220 continue; 7221 } 7222 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7223 switch (mode) { 7224 case INSERT_VALUES: 7225 for (p = 0; p < numPoints; p++) { 7226 const PetscInt point = points[2 * p]; 7227 const PetscInt *perm = perms ? perms[p] : NULL; 7228 const PetscScalar *flip = flips ? flips[p] : NULL; 7229 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7230 if (!contains) continue; 7231 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7232 } 7233 break; 7234 case INSERT_ALL_VALUES: 7235 for (p = 0; p < numPoints; p++) { 7236 const PetscInt point = points[2 * p]; 7237 const PetscInt *perm = perms ? perms[p] : NULL; 7238 const PetscScalar *flip = flips ? flips[p] : NULL; 7239 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7240 if (!contains) continue; 7241 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7242 } 7243 break; 7244 case INSERT_BC_VALUES: 7245 for (p = 0; p < numPoints; p++) { 7246 const PetscInt point = points[2 * p]; 7247 const PetscInt *perm = perms ? perms[p] : NULL; 7248 const PetscScalar *flip = flips ? flips[p] : NULL; 7249 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7250 if (!contains) continue; 7251 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7252 } 7253 break; 7254 case ADD_VALUES: 7255 for (p = 0; p < numPoints; p++) { 7256 const PetscInt point = points[2 * p]; 7257 const PetscInt *perm = perms ? perms[p] : NULL; 7258 const PetscScalar *flip = flips ? flips[p] : NULL; 7259 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7260 if (!contains) continue; 7261 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7262 } 7263 break; 7264 case ADD_ALL_VALUES: 7265 for (p = 0; p < numPoints; p++) { 7266 const PetscInt point = points[2 * p]; 7267 const PetscInt *perm = perms ? perms[p] : NULL; 7268 const PetscScalar *flip = flips ? flips[p] : NULL; 7269 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7270 if (!contains) continue; 7271 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7272 } 7273 break; 7274 default: 7275 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7276 } 7277 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7278 } 7279 /* Cleanup points */ 7280 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7281 /* Cleanup array */ 7282 PetscCall(VecRestoreArray(v, &array)); 7283 PetscFunctionReturn(PETSC_SUCCESS); 7284 } 7285 7286 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7287 { 7288 PetscMPIInt rank; 7289 PetscInt i, j; 7290 7291 PetscFunctionBegin; 7292 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7293 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7294 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7295 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7296 numCIndices = numCIndices ? numCIndices : numRIndices; 7297 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7298 for (i = 0; i < numRIndices; i++) { 7299 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7300 for (j = 0; j < numCIndices; j++) { 7301 #if defined(PETSC_USE_COMPLEX) 7302 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7303 #else 7304 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7305 #endif 7306 } 7307 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7308 } 7309 PetscFunctionReturn(PETSC_SUCCESS); 7310 } 7311 7312 /* 7313 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7314 7315 Input Parameters: 7316 + section - The section for this data layout 7317 . islocal - Is the section (and thus indices being requested) local or global? 7318 . point - The point contributing dofs with these indices 7319 . off - The global offset of this point 7320 . loff - The local offset of each field 7321 . setBC - The flag determining whether to include indices of boundary values 7322 . perm - A permutation of the dofs on this point, or NULL 7323 - indperm - A permutation of the entire indices array, or NULL 7324 7325 Output Parameter: 7326 . indices - Indices for dofs on this point 7327 7328 Level: developer 7329 7330 Note: The indices could be local or global, depending on the value of 'off'. 7331 */ 7332 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7333 { 7334 PetscInt dof; /* The number of unknowns on this point */ 7335 PetscInt cdof; /* The number of constraints on this point */ 7336 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7337 PetscInt cind = 0, k; 7338 7339 PetscFunctionBegin; 7340 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7341 PetscCall(PetscSectionGetDof(section, point, &dof)); 7342 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7343 if (!cdof || setBC) { 7344 for (k = 0; k < dof; ++k) { 7345 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7346 const PetscInt ind = indperm ? indperm[preind] : preind; 7347 7348 indices[ind] = off + k; 7349 } 7350 } else { 7351 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7352 for (k = 0; k < dof; ++k) { 7353 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7354 const PetscInt ind = indperm ? indperm[preind] : preind; 7355 7356 if ((cind < cdof) && (k == cdofs[cind])) { 7357 /* Insert check for returning constrained indices */ 7358 indices[ind] = -(off + k + 1); 7359 ++cind; 7360 } else { 7361 indices[ind] = off + k - (islocal ? 0 : cind); 7362 } 7363 } 7364 } 7365 *loff += dof; 7366 PetscFunctionReturn(PETSC_SUCCESS); 7367 } 7368 7369 /* 7370 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7371 7372 Input Parameters: 7373 + section - a section (global or local) 7374 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7375 . point - point within section 7376 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7377 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7378 . setBC - identify constrained (boundary condition) points via involution. 7379 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7380 . permsoff - offset 7381 - indperm - index permutation 7382 7383 Output Parameter: 7384 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7385 . indices - array to hold indices (as defined by section) of each dof associated with point 7386 7387 Notes: 7388 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7389 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7390 in the local vector. 7391 7392 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7393 significant). It is invalid to call with a global section and setBC=true. 7394 7395 Developer Note: 7396 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7397 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7398 offset could be obtained from the section instead of passing it explicitly as we do now. 7399 7400 Example: 7401 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7402 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7403 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7404 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. 7405 7406 Level: developer 7407 */ 7408 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[]) 7409 { 7410 PetscInt numFields, foff, f; 7411 7412 PetscFunctionBegin; 7413 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7414 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7415 for (f = 0, foff = 0; f < numFields; ++f) { 7416 PetscInt fdof, cfdof; 7417 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7418 PetscInt cind = 0, b; 7419 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7420 7421 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7422 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7423 if (!cfdof || setBC) { 7424 for (b = 0; b < fdof; ++b) { 7425 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7426 const PetscInt ind = indperm ? indperm[preind] : preind; 7427 7428 indices[ind] = off + foff + b; 7429 } 7430 } else { 7431 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7432 for (b = 0; b < fdof; ++b) { 7433 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7434 const PetscInt ind = indperm ? indperm[preind] : preind; 7435 7436 if ((cind < cfdof) && (b == fcdofs[cind])) { 7437 indices[ind] = -(off + foff + b + 1); 7438 ++cind; 7439 } else { 7440 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7441 } 7442 } 7443 } 7444 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7445 foffs[f] += fdof; 7446 } 7447 PetscFunctionReturn(PETSC_SUCCESS); 7448 } 7449 7450 /* 7451 This version believes the globalSection offsets for each field, rather than just the point offset 7452 7453 . foffs - The offset into 'indices' for each field, since it is segregated by field 7454 7455 Notes: 7456 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7457 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7458 */ 7459 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7460 { 7461 PetscInt numFields, foff, f; 7462 7463 PetscFunctionBegin; 7464 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7465 for (f = 0; f < numFields; ++f) { 7466 PetscInt fdof, cfdof; 7467 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7468 PetscInt cind = 0, b; 7469 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7470 7471 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7472 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7473 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7474 if (!cfdof) { 7475 for (b = 0; b < fdof; ++b) { 7476 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7477 const PetscInt ind = indperm ? indperm[preind] : preind; 7478 7479 indices[ind] = foff + b; 7480 } 7481 } else { 7482 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7483 for (b = 0; b < fdof; ++b) { 7484 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7485 const PetscInt ind = indperm ? indperm[preind] : preind; 7486 7487 if ((cind < cfdof) && (b == fcdofs[cind])) { 7488 indices[ind] = -(foff + b + 1); 7489 ++cind; 7490 } else { 7491 indices[ind] = foff + b - cind; 7492 } 7493 } 7494 } 7495 foffs[f] += fdof; 7496 } 7497 PetscFunctionReturn(PETSC_SUCCESS); 7498 } 7499 7500 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7501 { 7502 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7503 7504 PetscFunctionBegin; 7505 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7506 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7507 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7508 for (PetscInt p = 0; p < nPoints; p++) { 7509 PetscInt b = pnts[2 * p]; 7510 PetscInt bSecDof = 0, bOff; 7511 PetscInt cSecDof = 0; 7512 PetscSection indices_section; 7513 7514 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7515 if (!bSecDof) continue; 7516 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7517 indices_section = cSecDof > 0 ? cSec : section; 7518 if (numFields) { 7519 PetscInt fStart[32], fEnd[32]; 7520 7521 fStart[0] = 0; 7522 fEnd[0] = 0; 7523 for (PetscInt f = 0; f < numFields; f++) { 7524 PetscInt fDof = 0; 7525 7526 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7527 fStart[f + 1] = fStart[f] + fDof; 7528 fEnd[f + 1] = fStart[f + 1]; 7529 } 7530 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7531 // only apply permutations on one side 7532 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7533 for (PetscInt f = 0; f < numFields; f++) { 7534 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7535 } 7536 } else { 7537 PetscInt bEnd = 0; 7538 7539 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7540 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7541 7542 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7543 } 7544 } 7545 PetscFunctionReturn(PETSC_SUCCESS); 7546 } 7547 7548 PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[]) 7549 { 7550 Mat cMat; 7551 PetscSection aSec, cSec; 7552 IS aIS; 7553 PetscInt aStart = -1, aEnd = -1; 7554 PetscInt sStart = -1, sEnd = -1; 7555 PetscInt cStart = -1, cEnd = -1; 7556 const PetscInt *anchors; 7557 PetscInt numFields, p; 7558 PetscInt newNumPoints = 0, newNumIndices = 0; 7559 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7560 PetscInt oldOffsets[32]; 7561 PetscInt newOffsets[32]; 7562 PetscInt oldOffsetsCopy[32]; 7563 PetscInt newOffsetsCopy[32]; 7564 PetscScalar *modMat = NULL; 7565 PetscBool anyConstrained = PETSC_FALSE; 7566 7567 PetscFunctionBegin; 7568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7569 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7570 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7571 7572 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7573 /* if there are point-to-point constraints */ 7574 if (aSec) { 7575 PetscCall(PetscArrayzero(newOffsets, 32)); 7576 PetscCall(PetscArrayzero(oldOffsets, 32)); 7577 PetscCall(ISGetIndices(aIS, &anchors)); 7578 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7579 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7580 /* figure out how many points are going to be in the new element matrix 7581 * (we allow double counting, because it's all just going to be summed 7582 * into the global matrix anyway) */ 7583 for (p = 0; p < 2 * numPoints; p += 2) { 7584 PetscInt b = points[p]; 7585 PetscInt bDof = 0, bSecDof = 0; 7586 7587 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7588 if (!bSecDof) continue; 7589 7590 for (PetscInt f = 0; f < numFields; f++) { 7591 PetscInt fDof = 0; 7592 7593 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7594 oldOffsets[f + 1] += fDof; 7595 } 7596 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7597 if (bDof) { 7598 /* this point is constrained */ 7599 /* it is going to be replaced by its anchors */ 7600 PetscInt bOff, q; 7601 7602 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7603 for (q = 0; q < bDof; q++) { 7604 PetscInt a = anchors[bOff + q]; 7605 PetscInt aDof = 0; 7606 7607 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7608 if (aDof) { 7609 anyConstrained = PETSC_TRUE; 7610 newNumPoints += 1; 7611 } 7612 newNumIndices += aDof; 7613 for (PetscInt f = 0; f < numFields; ++f) { 7614 PetscInt fDof = 0; 7615 7616 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7617 newOffsets[f + 1] += fDof; 7618 } 7619 } 7620 } else { 7621 /* this point is not constrained */ 7622 newNumPoints++; 7623 newNumIndices += bSecDof; 7624 for (PetscInt f = 0; f < numFields; ++f) { 7625 PetscInt fDof; 7626 7627 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7628 newOffsets[f + 1] += fDof; 7629 } 7630 } 7631 } 7632 } 7633 if (!anyConstrained) { 7634 if (outNumPoints) *outNumPoints = 0; 7635 if (outNumIndices) *outNumIndices = 0; 7636 if (outPoints) *outPoints = NULL; 7637 if (outMat) *outMat = NULL; 7638 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7639 PetscFunctionReturn(PETSC_SUCCESS); 7640 } 7641 7642 if (outNumPoints) *outNumPoints = newNumPoints; 7643 if (outNumIndices) *outNumIndices = newNumIndices; 7644 7645 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7646 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7647 7648 if (!outPoints && !outMat) { 7649 if (offsets) { 7650 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7651 } 7652 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7653 PetscFunctionReturn(PETSC_SUCCESS); 7654 } 7655 7656 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7657 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7658 7659 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7660 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7661 7662 /* output arrays */ 7663 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7664 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7665 7666 // get the new Points 7667 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7668 PetscInt b = points[2 * p]; 7669 PetscInt bDof = 0, bSecDof = 0, bOff; 7670 7671 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7672 if (!bSecDof) continue; 7673 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7674 if (bDof) { 7675 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7676 for (PetscInt q = 0; q < bDof; q++) { 7677 PetscInt a = anchors[bOff + q], aDof = 0; 7678 7679 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7680 if (aDof) { 7681 newPoints[2 * newP] = a; 7682 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7683 newP++; 7684 } 7685 } 7686 } else { 7687 newPoints[2 * newP] = b; 7688 newPoints[2 * newP + 1] = points[2 * p + 1]; 7689 newP++; 7690 } 7691 } 7692 7693 if (outMat) { 7694 PetscScalar *tmpMat; 7695 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7696 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7697 7698 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7699 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7700 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7701 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7702 7703 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7704 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7705 7706 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7707 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7708 7709 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7710 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7711 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7712 // for each field, insert the anchor modification into modMat 7713 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7714 PetscInt fStart = oldOffsets[f]; 7715 PetscInt fNewStart = newOffsets[f]; 7716 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7717 PetscInt b = points[2 * p]; 7718 PetscInt bDof = 0, bSecDof = 0, bOff; 7719 7720 if (b >= sStart && b < sEnd) { 7721 if (numFields) { 7722 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7723 } else { 7724 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7725 } 7726 } 7727 if (!bSecDof) continue; 7728 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7729 if (bDof) { 7730 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7731 for (PetscInt q = 0; q < bDof; q++, newP++) { 7732 PetscInt a = anchors[bOff + q], aDof = 0; 7733 7734 if (a >= sStart && a < sEnd) { 7735 if (numFields) { 7736 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7737 } else { 7738 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7739 } 7740 } 7741 if (aDof) { 7742 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7743 for (PetscInt d = 0; d < bSecDof; d++) { 7744 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7745 } 7746 } 7747 oNew += aDof; 7748 } 7749 } else { 7750 // Insert the identity matrix in this block 7751 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7752 oNew += bSecDof; 7753 newP++; 7754 } 7755 o += bSecDof; 7756 } 7757 } 7758 7759 *outMat = modMat; 7760 7761 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7762 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7763 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7764 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7765 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7766 } 7767 PetscCall(ISRestoreIndices(aIS, &anchors)); 7768 7769 /* output */ 7770 if (outPoints) { 7771 *outPoints = newPoints; 7772 } else { 7773 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7774 } 7775 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7776 PetscFunctionReturn(PETSC_SUCCESS); 7777 } 7778 7779 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat_Internal(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt numRows, PetscInt numCols, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyRight, PetscBool multiplyLeft) 7780 { 7781 PetscScalar *modMat = NULL; 7782 PetscInt newNumIndices = -1; 7783 7784 PetscFunctionBegin; 7785 /* If M is the matrix represented by values, get the matrix C such that we will add M * C (or, if multiplyLeft, C^T * M * C) into the global matrix. 7786 modMat is that matrix C */ 7787 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7788 if (outNumIndices) *outNumIndices = newNumIndices; 7789 if (modMat) { 7790 const PetscScalar *newValues = values; 7791 7792 if (multiplyRight) { 7793 PetscScalar *newNewValues = NULL; 7794 PetscBLASInt M, N, K; 7795 PetscScalar a = 1.0, b = 0.0; 7796 7797 PetscCheck(numCols == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of columns: %" PetscInt_FMT ", expected %" PetscInt_FMT, numCols, numIndices); 7798 7799 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7800 PetscCall(PetscBLASIntCast(numRows, &N)); 7801 PetscCall(PetscBLASIntCast(numIndices, &K)); 7802 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7803 // row-major to column-major conversion, right multiplication becomes left multiplication 7804 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7805 numCols = newNumIndices; 7806 newValues = newNewValues; 7807 } 7808 7809 if (multiplyLeft) { 7810 PetscScalar *newNewValues = NULL; 7811 PetscBLASInt M, N, K; 7812 PetscScalar a = 1.0, b = 0.0; 7813 7814 PetscCheck(numRows == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of rows: %" PetscInt_FMT ", expected %" PetscInt_FMT, numRows, numIndices); 7815 7816 PetscCall(PetscBLASIntCast(numCols, &M)); 7817 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7818 PetscCall(PetscBLASIntCast(numIndices, &K)); 7819 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7820 // row-major to column-major conversion, left multiplication becomes right multiplication 7821 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7822 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7823 newValues = newNewValues; 7824 } 7825 *outValues = (PetscScalar *)newValues; 7826 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7827 } 7828 PetscFunctionReturn(PETSC_SUCCESS); 7829 } 7830 7831 PETSC_INTERN 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) 7832 { 7833 PetscFunctionBegin; 7834 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7835 PetscFunctionReturn(PETSC_SUCCESS); 7836 } 7837 7838 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7839 { 7840 /* Closure ordering */ 7841 PetscSection clSection; 7842 IS clPoints; 7843 const PetscInt *clp; 7844 PetscInt *points; 7845 PetscInt Ncl, Ni = 0; 7846 7847 PetscFunctionBeginHot; 7848 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7849 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7850 PetscInt dof; 7851 7852 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7853 Ni += dof; 7854 } 7855 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7856 *closureSize = Ni; 7857 PetscFunctionReturn(PETSC_SUCCESS); 7858 } 7859 7860 static PetscErrorCode DMPlexGetClosureIndices_Internal(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numRows, PetscInt *numCols, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[], PetscBool multiplyRight, PetscBool multiplyLeft) 7861 { 7862 /* Closure ordering */ 7863 PetscSection clSection; 7864 IS clPoints; 7865 const PetscInt *clp; 7866 PetscInt *points; 7867 const PetscInt *clperm = NULL; 7868 /* Dof permutation and sign flips */ 7869 const PetscInt **perms[32] = {NULL}; 7870 const PetscScalar **flips[32] = {NULL}; 7871 PetscScalar *valCopy = NULL; 7872 /* Hanging node constraints */ 7873 PetscInt *pointsC = NULL; 7874 PetscScalar *valuesC = NULL; 7875 PetscInt NclC, NiC; 7876 7877 PetscInt *idx; 7878 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7879 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7880 PetscInt idxStart, idxEnd; 7881 PetscInt nRows, nCols; 7882 7883 PetscFunctionBeginHot; 7884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7885 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7886 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7887 PetscAssertPointer(numRows, 6); 7888 PetscAssertPointer(numCols, 7); 7889 if (indices) PetscAssertPointer(indices, 8); 7890 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7891 if (values) PetscAssertPointer(values, 10); 7892 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7893 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7894 PetscCall(PetscArrayzero(offsets, 32)); 7895 /* 1) Get points in closure */ 7896 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7897 if (useClPerm) { 7898 PetscInt depth, clsize; 7899 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7900 for (clsize = 0, p = 0; p < Ncl; p++) { 7901 PetscInt dof; 7902 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7903 clsize += dof; 7904 } 7905 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7906 } 7907 /* 2) Get number of indices on these points and field offsets from section */ 7908 for (p = 0; p < Ncl * 2; p += 2) { 7909 PetscInt dof, fdof; 7910 7911 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7912 for (f = 0; f < Nf; ++f) { 7913 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7914 offsets[f + 1] += fdof; 7915 } 7916 Ni += dof; 7917 } 7918 if (*numRows == -1) *numRows = Ni; 7919 if (*numCols == -1) *numCols = Ni; 7920 nRows = *numRows; 7921 nCols = *numCols; 7922 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7923 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7924 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7925 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7926 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7927 for (f = 0; f < PetscMax(1, Nf); ++f) { 7928 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7929 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7930 /* may need to apply sign changes to the element matrix */ 7931 if (values && flips[f]) { 7932 PetscInt foffset = offsets[f]; 7933 7934 for (p = 0; p < Ncl; ++p) { 7935 PetscInt pnt = points[2 * p], fdof; 7936 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7937 7938 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7939 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7940 if (flip) { 7941 PetscInt i, j, k; 7942 7943 if (!valCopy) { 7944 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7945 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7946 *values = valCopy; 7947 } 7948 for (i = 0; i < fdof; ++i) { 7949 PetscScalar fval = flip[i]; 7950 7951 if (multiplyRight) { 7952 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7953 } 7954 if (multiplyLeft) { 7955 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7956 } 7957 } 7958 } 7959 foffset += fdof; 7960 } 7961 } 7962 } 7963 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7964 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7965 if (NclC) { 7966 if (multiplyRight) *numCols = NiC; 7967 if (multiplyLeft) *numRows = NiC; 7968 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7969 for (f = 0; f < PetscMax(1, Nf); ++f) { 7970 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7971 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7972 } 7973 for (f = 0; f < PetscMax(1, Nf); ++f) { 7974 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7975 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7976 } 7977 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7978 Ncl = NclC; 7979 Ni = NiC; 7980 points = pointsC; 7981 if (values) *values = valuesC; 7982 } 7983 /* 5) Calculate indices */ 7984 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7985 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 7986 if (Nf) { 7987 PetscInt idxOff; 7988 PetscBool useFieldOffsets; 7989 7990 if (outOffsets) { 7991 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7992 } 7993 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7994 if (useFieldOffsets) { 7995 for (p = 0; p < Ncl; ++p) { 7996 const PetscInt pnt = points[p * 2]; 7997 7998 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7999 } 8000 } else { 8001 for (p = 0; p < Ncl; ++p) { 8002 const PetscInt pnt = points[p * 2]; 8003 8004 if (pnt < idxStart || pnt >= idxEnd) continue; 8005 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8006 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8007 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8008 * global section. */ 8009 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8010 } 8011 } 8012 } else { 8013 PetscInt off = 0, idxOff; 8014 8015 for (p = 0; p < Ncl; ++p) { 8016 const PetscInt pnt = points[p * 2]; 8017 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8018 8019 if (pnt < idxStart || pnt >= idxEnd) continue; 8020 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8021 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8022 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8023 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8024 } 8025 } 8026 /* 6) Cleanup */ 8027 for (f = 0; f < PetscMax(1, Nf); ++f) { 8028 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8029 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8030 } 8031 if (NclC) { 8032 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8033 } else { 8034 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8035 } 8036 8037 if (indices) *indices = idx; 8038 PetscFunctionReturn(PETSC_SUCCESS); 8039 } 8040 8041 /*@C 8042 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8043 8044 Not collective 8045 8046 Input Parameters: 8047 + dm - The `DM` 8048 . section - The `PetscSection` describing the points (a local section) 8049 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8050 . point - The point defining the closure 8051 - useClPerm - Use the closure point permutation if available 8052 8053 Output Parameters: 8054 + numIndices - The number of dof indices in the closure of point with the input sections 8055 . indices - The dof indices 8056 . outOffsets - Array to write the field offsets into, or `NULL` 8057 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8058 8059 Level: advanced 8060 8061 Notes: 8062 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8063 8064 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8065 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8066 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8067 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8068 indices (with the above semantics) are implied. 8069 8070 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8071 `PetscSection`, `DMGetGlobalSection()` 8072 @*/ 8073 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8074 { 8075 PetscInt numRows = -1, numCols = -1; 8076 8077 PetscFunctionBeginHot; 8078 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8079 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8080 *numIndices = numRows; 8081 PetscFunctionReturn(PETSC_SUCCESS); 8082 } 8083 8084 /*@C 8085 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8086 8087 Not collective 8088 8089 Input Parameters: 8090 + dm - The `DM` 8091 . section - The `PetscSection` describing the points (a local section) 8092 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8093 . point - The point defining the closure 8094 - useClPerm - Use the closure point permutation if available 8095 8096 Output Parameters: 8097 + numIndices - The number of dof indices in the closure of point with the input sections 8098 . indices - The dof indices 8099 . outOffsets - Array to write the field offsets into, or `NULL` 8100 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8101 8102 Level: advanced 8103 8104 Notes: 8105 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8106 8107 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8108 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8109 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8110 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8111 indices (with the above semantics) are implied. 8112 8113 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8114 @*/ 8115 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8116 { 8117 PetscFunctionBegin; 8118 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8119 PetscAssertPointer(indices, 7); 8120 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8121 PetscFunctionReturn(PETSC_SUCCESS); 8122 } 8123 8124 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8125 { 8126 DM_Plex *mesh = (DM_Plex *)dm->data; 8127 PetscInt *indices; 8128 PetscInt numIndices; 8129 const PetscScalar *valuesOrig = values; 8130 PetscErrorCode ierr; 8131 8132 PetscFunctionBegin; 8133 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8134 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8135 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8136 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8137 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8138 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8139 8140 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8141 8142 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8143 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8144 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8145 if (ierr) { 8146 PetscMPIInt rank; 8147 8148 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8149 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8150 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8151 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8152 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8153 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8154 } 8155 if (mesh->printFEM > 1) { 8156 PetscInt i; 8157 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8158 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8159 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8160 } 8161 8162 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8163 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8164 PetscFunctionReturn(PETSC_SUCCESS); 8165 } 8166 8167 /*@C 8168 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8169 8170 Not collective 8171 8172 Input Parameters: 8173 + dm - The `DM` 8174 . section - The section describing the layout in `v`, or `NULL` to use the default section 8175 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8176 . A - The matrix 8177 . point - The point in the `DM` 8178 . values - The array of values 8179 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8180 8181 Level: intermediate 8182 8183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8184 @*/ 8185 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8186 { 8187 PetscFunctionBegin; 8188 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8189 PetscFunctionReturn(PETSC_SUCCESS); 8190 } 8191 8192 /*@C 8193 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8194 8195 Not collective 8196 8197 Input Parameters: 8198 + dmRow - The `DM` for the row fields 8199 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8200 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8201 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8202 . dmCol - The `DM` for the column fields 8203 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8204 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8205 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8206 . A - The matrix 8207 . point - The point in the `DM` 8208 . values - The array of values 8209 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8210 8211 Level: intermediate 8212 8213 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8214 @*/ 8215 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) 8216 { 8217 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8218 PetscInt *indicesRow, *indicesCol; 8219 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8220 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8221 8222 PetscErrorCode ierr; 8223 8224 PetscFunctionBegin; 8225 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8226 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8227 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8228 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8229 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8230 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8231 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8232 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8233 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8234 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8235 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8236 8237 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8238 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8239 valuesV1 = valuesV0; 8240 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8241 valuesV2 = valuesV1; 8242 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8243 8244 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8245 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8246 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8247 if (ierr) { 8248 PetscMPIInt rank; 8249 8250 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8251 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8252 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8253 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8254 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8255 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8256 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8257 } 8258 8259 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8260 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8261 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8262 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8263 PetscFunctionReturn(PETSC_SUCCESS); 8264 } 8265 8266 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8267 { 8268 DM_Plex *mesh = (DM_Plex *)dmf->data; 8269 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8270 PetscInt *cpoints = NULL; 8271 PetscInt *findices, *cindices; 8272 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8273 PetscInt foffsets[32], coffsets[32]; 8274 DMPolytopeType ct; 8275 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8276 PetscErrorCode ierr; 8277 8278 PetscFunctionBegin; 8279 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8280 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8281 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8282 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8283 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8284 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8285 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8286 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8287 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8288 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8289 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8290 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8291 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8292 PetscCall(PetscArrayzero(foffsets, 32)); 8293 PetscCall(PetscArrayzero(coffsets, 32)); 8294 /* Column indices */ 8295 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8296 maxFPoints = numCPoints; 8297 /* Compress out points not in the section */ 8298 /* TODO: Squeeze out points with 0 dof as well */ 8299 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8300 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8301 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8302 cpoints[q * 2] = cpoints[p]; 8303 cpoints[q * 2 + 1] = cpoints[p + 1]; 8304 ++q; 8305 } 8306 } 8307 numCPoints = q; 8308 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8309 PetscInt fdof; 8310 8311 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8312 if (!dof) continue; 8313 for (f = 0; f < numFields; ++f) { 8314 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8315 coffsets[f + 1] += fdof; 8316 } 8317 numCIndices += dof; 8318 } 8319 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8320 /* Row indices */ 8321 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8322 { 8323 DMPlexTransform tr; 8324 DMPolytopeType *rct; 8325 PetscInt *rsize, *rcone, *rornt, Nt; 8326 8327 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8328 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8329 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8330 numSubcells = rsize[Nt - 1]; 8331 PetscCall(DMPlexTransformDestroy(&tr)); 8332 } 8333 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8334 for (r = 0, q = 0; r < numSubcells; ++r) { 8335 /* TODO Map from coarse to fine cells */ 8336 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8337 /* Compress out points not in the section */ 8338 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8339 for (p = 0; p < numFPoints * 2; p += 2) { 8340 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8341 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8342 if (!dof) continue; 8343 for (s = 0; s < q; ++s) 8344 if (fpoints[p] == ftotpoints[s * 2]) break; 8345 if (s < q) continue; 8346 ftotpoints[q * 2] = fpoints[p]; 8347 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8348 ++q; 8349 } 8350 } 8351 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8352 } 8353 numFPoints = q; 8354 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8355 PetscInt fdof; 8356 8357 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8358 if (!dof) continue; 8359 for (f = 0; f < numFields; ++f) { 8360 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8361 foffsets[f + 1] += fdof; 8362 } 8363 numFIndices += dof; 8364 } 8365 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8366 8367 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8368 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8369 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8370 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8371 if (numFields) { 8372 const PetscInt **permsF[32] = {NULL}; 8373 const PetscInt **permsC[32] = {NULL}; 8374 8375 for (f = 0; f < numFields; f++) { 8376 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8377 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8378 } 8379 for (p = 0; p < numFPoints; p++) { 8380 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8381 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8382 } 8383 for (p = 0; p < numCPoints; p++) { 8384 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8385 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8386 } 8387 for (f = 0; f < numFields; f++) { 8388 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8389 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8390 } 8391 } else { 8392 const PetscInt **permsF = NULL; 8393 const PetscInt **permsC = NULL; 8394 8395 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8396 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8397 for (p = 0, off = 0; p < numFPoints; p++) { 8398 const PetscInt *perm = permsF ? permsF[p] : NULL; 8399 8400 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8401 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8402 } 8403 for (p = 0, off = 0; p < numCPoints; p++) { 8404 const PetscInt *perm = permsC ? permsC[p] : NULL; 8405 8406 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8407 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8408 } 8409 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8410 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8411 } 8412 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8413 /* TODO: flips */ 8414 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8415 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8416 if (ierr) { 8417 PetscMPIInt rank; 8418 8419 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8420 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8421 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8422 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8423 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8424 } 8425 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8426 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8427 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8428 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8429 PetscFunctionReturn(PETSC_SUCCESS); 8430 } 8431 8432 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8433 { 8434 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8435 PetscInt *cpoints = NULL; 8436 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8437 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8438 DMPolytopeType ct; 8439 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8440 8441 PetscFunctionBegin; 8442 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8443 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8444 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8445 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8446 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8447 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8448 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8449 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8450 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8451 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8452 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8453 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8454 /* Column indices */ 8455 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8456 maxFPoints = numCPoints; 8457 /* Compress out points not in the section */ 8458 /* TODO: Squeeze out points with 0 dof as well */ 8459 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8460 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8461 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8462 cpoints[q * 2] = cpoints[p]; 8463 cpoints[q * 2 + 1] = cpoints[p + 1]; 8464 ++q; 8465 } 8466 } 8467 numCPoints = q; 8468 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8469 PetscInt fdof; 8470 8471 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8472 if (!dof) continue; 8473 for (f = 0; f < numFields; ++f) { 8474 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8475 coffsets[f + 1] += fdof; 8476 } 8477 numCIndices += dof; 8478 } 8479 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8480 /* Row indices */ 8481 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8482 { 8483 DMPlexTransform tr; 8484 DMPolytopeType *rct; 8485 PetscInt *rsize, *rcone, *rornt, Nt; 8486 8487 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8488 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8489 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8490 numSubcells = rsize[Nt - 1]; 8491 PetscCall(DMPlexTransformDestroy(&tr)); 8492 } 8493 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8494 for (r = 0, q = 0; r < numSubcells; ++r) { 8495 /* TODO Map from coarse to fine cells */ 8496 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8497 /* Compress out points not in the section */ 8498 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8499 for (p = 0; p < numFPoints * 2; p += 2) { 8500 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8501 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8502 if (!dof) continue; 8503 for (s = 0; s < q; ++s) 8504 if (fpoints[p] == ftotpoints[s * 2]) break; 8505 if (s < q) continue; 8506 ftotpoints[q * 2] = fpoints[p]; 8507 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8508 ++q; 8509 } 8510 } 8511 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8512 } 8513 numFPoints = q; 8514 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8515 PetscInt fdof; 8516 8517 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8518 if (!dof) continue; 8519 for (f = 0; f < numFields; ++f) { 8520 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8521 foffsets[f + 1] += fdof; 8522 } 8523 numFIndices += dof; 8524 } 8525 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8526 8527 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8528 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8529 if (numFields) { 8530 const PetscInt **permsF[32] = {NULL}; 8531 const PetscInt **permsC[32] = {NULL}; 8532 8533 for (f = 0; f < numFields; f++) { 8534 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8535 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8536 } 8537 for (p = 0; p < numFPoints; p++) { 8538 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8539 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8540 } 8541 for (p = 0; p < numCPoints; p++) { 8542 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8543 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8544 } 8545 for (f = 0; f < numFields; f++) { 8546 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8547 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8548 } 8549 } else { 8550 const PetscInt **permsF = NULL; 8551 const PetscInt **permsC = NULL; 8552 8553 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8554 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8555 for (p = 0, off = 0; p < numFPoints; p++) { 8556 const PetscInt *perm = permsF ? permsF[p] : NULL; 8557 8558 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8559 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8560 } 8561 for (p = 0, off = 0; p < numCPoints; p++) { 8562 const PetscInt *perm = permsC ? permsC[p] : NULL; 8563 8564 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8565 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8566 } 8567 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8568 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8569 } 8570 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8571 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8572 PetscFunctionReturn(PETSC_SUCCESS); 8573 } 8574 8575 /*@ 8576 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8577 8578 Input Parameter: 8579 . dm - The `DMPLEX` object 8580 8581 Output Parameter: 8582 . cellHeight - The height of a cell 8583 8584 Level: developer 8585 8586 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8587 @*/ 8588 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8589 { 8590 DM_Plex *mesh = (DM_Plex *)dm->data; 8591 8592 PetscFunctionBegin; 8593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8594 PetscAssertPointer(cellHeight, 2); 8595 *cellHeight = mesh->vtkCellHeight; 8596 PetscFunctionReturn(PETSC_SUCCESS); 8597 } 8598 8599 /*@ 8600 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8601 8602 Input Parameters: 8603 + dm - The `DMPLEX` object 8604 - cellHeight - The height of a cell 8605 8606 Level: developer 8607 8608 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8609 @*/ 8610 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8611 { 8612 DM_Plex *mesh = (DM_Plex *)dm->data; 8613 8614 PetscFunctionBegin; 8615 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8616 mesh->vtkCellHeight = cellHeight; 8617 PetscFunctionReturn(PETSC_SUCCESS); 8618 } 8619 8620 /*@ 8621 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8622 8623 Input Parameters: 8624 + dm - The `DMPLEX` object 8625 - ct - The `DMPolytopeType` of the cell 8626 8627 Output Parameters: 8628 + start - The first cell of this type, or `NULL` 8629 - end - The upper bound on this celltype, or `NULL` 8630 8631 Level: advanced 8632 8633 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8634 @*/ 8635 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8636 { 8637 DM_Plex *mesh = (DM_Plex *)dm->data; 8638 DMLabel label; 8639 PetscInt pStart, pEnd; 8640 8641 PetscFunctionBegin; 8642 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8643 if (start) { 8644 PetscAssertPointer(start, 3); 8645 *start = 0; 8646 } 8647 if (end) { 8648 PetscAssertPointer(end, 4); 8649 *end = 0; 8650 } 8651 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8652 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8653 if (mesh->tr) { 8654 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8655 } else { 8656 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8657 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8658 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8659 } 8660 PetscFunctionReturn(PETSC_SUCCESS); 8661 } 8662 8663 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8664 { 8665 PetscSection section, globalSection; 8666 PetscInt *numbers, p; 8667 8668 PetscFunctionBegin; 8669 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8670 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8671 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8672 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8673 PetscCall(PetscSectionSetUp(section)); 8674 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8675 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8676 for (p = pStart; p < pEnd; ++p) { 8677 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8678 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8679 else numbers[p - pStart] += shift; 8680 } 8681 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8682 if (globalSize) { 8683 PetscLayout layout; 8684 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8685 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8686 PetscCall(PetscLayoutDestroy(&layout)); 8687 } 8688 PetscCall(PetscSectionDestroy(§ion)); 8689 PetscCall(PetscSectionDestroy(&globalSection)); 8690 PetscFunctionReturn(PETSC_SUCCESS); 8691 } 8692 8693 /*@ 8694 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8695 8696 Input Parameters: 8697 + dm - The `DMPLEX` object 8698 - includeAll - Whether to include all cells, or just the simplex and box cells 8699 8700 Output Parameter: 8701 . globalCellNumbers - Global cell numbers for all cells on this process 8702 8703 Level: developer 8704 8705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8706 @*/ 8707 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8708 { 8709 PetscInt cellHeight, cStart, cEnd; 8710 8711 PetscFunctionBegin; 8712 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8713 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8714 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8715 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8716 PetscFunctionReturn(PETSC_SUCCESS); 8717 } 8718 8719 /*@ 8720 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8721 8722 Input Parameter: 8723 . dm - The `DMPLEX` object 8724 8725 Output Parameter: 8726 . globalCellNumbers - Global cell numbers for all cells on this process 8727 8728 Level: developer 8729 8730 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8731 @*/ 8732 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8733 { 8734 DM_Plex *mesh = (DM_Plex *)dm->data; 8735 8736 PetscFunctionBegin; 8737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8738 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8739 *globalCellNumbers = mesh->globalCellNumbers; 8740 PetscFunctionReturn(PETSC_SUCCESS); 8741 } 8742 8743 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8744 { 8745 PetscInt vStart, vEnd; 8746 8747 PetscFunctionBegin; 8748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8749 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8750 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8751 PetscFunctionReturn(PETSC_SUCCESS); 8752 } 8753 8754 /*@ 8755 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8756 8757 Input Parameter: 8758 . dm - The `DMPLEX` object 8759 8760 Output Parameter: 8761 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8762 8763 Level: developer 8764 8765 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8766 @*/ 8767 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8768 { 8769 DM_Plex *mesh = (DM_Plex *)dm->data; 8770 8771 PetscFunctionBegin; 8772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8773 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8774 *globalVertexNumbers = mesh->globalVertexNumbers; 8775 PetscFunctionReturn(PETSC_SUCCESS); 8776 } 8777 8778 /*@ 8779 DMPlexCreatePointNumbering - Create a global numbering for all points. 8780 8781 Collective 8782 8783 Input Parameter: 8784 . dm - The `DMPLEX` object 8785 8786 Output Parameter: 8787 . globalPointNumbers - Global numbers for all points on this process 8788 8789 Level: developer 8790 8791 Notes: 8792 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8793 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8794 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8795 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8796 8797 The partitioned mesh is 8798 ``` 8799 (2)--0--(3)--1--(4) (1)--0--(2) 8800 ``` 8801 and its global numbering is 8802 ``` 8803 (3)--0--(4)--1--(5)--2--(6) 8804 ``` 8805 Then the global numbering is provided as 8806 ``` 8807 [0] Number of indices in set 5 8808 [0] 0 0 8809 [0] 1 1 8810 [0] 2 3 8811 [0] 3 4 8812 [0] 4 -6 8813 [1] Number of indices in set 3 8814 [1] 0 2 8815 [1] 1 5 8816 [1] 2 6 8817 ``` 8818 8819 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8820 @*/ 8821 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8822 { 8823 IS nums[4]; 8824 PetscInt depths[4], gdepths[4], starts[4]; 8825 PetscInt depth, d, shift = 0; 8826 PetscBool empty = PETSC_FALSE; 8827 8828 PetscFunctionBegin; 8829 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8830 PetscCall(DMPlexGetDepth(dm, &depth)); 8831 // For unstratified meshes use dim instead of depth 8832 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8833 // If any stratum is empty, we must mark all empty 8834 for (d = 0; d <= depth; ++d) { 8835 PetscInt end; 8836 8837 depths[d] = depth - d; 8838 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8839 if (!(starts[d] - end)) empty = PETSC_TRUE; 8840 } 8841 if (empty) 8842 for (d = 0; d <= depth; ++d) { 8843 depths[d] = -1; 8844 starts[d] = -1; 8845 } 8846 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8847 PetscCallMPI(MPIU_Allreduce(depths, gdepths, (PetscMPIInt)(depth + 1), MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8848 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]); 8849 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8850 for (d = 0; d <= depth; ++d) { 8851 PetscInt pStart, pEnd, gsize; 8852 8853 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8854 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8855 shift += gsize; 8856 } 8857 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8858 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8859 PetscFunctionReturn(PETSC_SUCCESS); 8860 } 8861 8862 /*@ 8863 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8864 8865 Collective 8866 8867 Input Parameter: 8868 . dm - The `DMPLEX` object 8869 8870 Output Parameter: 8871 . globalEdgeNumbers - Global numbers for all edges on this process 8872 8873 Level: developer 8874 8875 Notes: 8876 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). In the IS, owned edges will have their non-negative value while edges owned by different ranks will be involuted -(idx+1). 8877 8878 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8879 @*/ 8880 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8881 { 8882 PetscSF sf; 8883 PetscInt eStart, eEnd; 8884 8885 PetscFunctionBegin; 8886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8887 PetscCall(DMGetPointSF(dm, &sf)); 8888 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8889 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8890 PetscFunctionReturn(PETSC_SUCCESS); 8891 } 8892 8893 /*@ 8894 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8895 8896 Input Parameter: 8897 . dm - The `DMPLEX` object 8898 8899 Output Parameter: 8900 . ranks - The rank field 8901 8902 Options Database Key: 8903 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8904 8905 Level: intermediate 8906 8907 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8908 @*/ 8909 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8910 { 8911 DM rdm; 8912 PetscFE fe; 8913 PetscScalar *r; 8914 PetscMPIInt rank; 8915 DMPolytopeType ct; 8916 PetscInt dim, cStart, cEnd, c; 8917 PetscBool simplex; 8918 8919 PetscFunctionBeginUser; 8920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8921 PetscAssertPointer(ranks, 2); 8922 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8923 PetscCall(DMClone(dm, &rdm)); 8924 PetscCall(DMGetDimension(rdm, &dim)); 8925 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8926 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8927 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8928 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8929 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8930 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8931 PetscCall(PetscFEDestroy(&fe)); 8932 PetscCall(DMCreateDS(rdm)); 8933 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8934 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8935 PetscCall(VecGetArray(*ranks, &r)); 8936 for (c = cStart; c < cEnd; ++c) { 8937 PetscScalar *lr; 8938 8939 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8940 if (lr) *lr = rank; 8941 } 8942 PetscCall(VecRestoreArray(*ranks, &r)); 8943 PetscCall(DMDestroy(&rdm)); 8944 PetscFunctionReturn(PETSC_SUCCESS); 8945 } 8946 8947 /*@ 8948 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8949 8950 Input Parameters: 8951 + dm - The `DMPLEX` 8952 - label - The `DMLabel` 8953 8954 Output Parameter: 8955 . val - The label value field 8956 8957 Options Database Key: 8958 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8959 8960 Level: intermediate 8961 8962 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8963 @*/ 8964 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8965 { 8966 DM rdm, plex; 8967 Vec lval; 8968 PetscSection section; 8969 PetscFE fe; 8970 PetscScalar *v; 8971 PetscInt dim, pStart, pEnd, p, cStart; 8972 DMPolytopeType ct; 8973 char name[PETSC_MAX_PATH_LEN]; 8974 const char *lname, *prefix; 8975 8976 PetscFunctionBeginUser; 8977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8978 PetscAssertPointer(label, 2); 8979 PetscAssertPointer(val, 3); 8980 PetscCall(DMClone(dm, &rdm)); 8981 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8982 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8983 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8984 PetscCall(DMDestroy(&plex)); 8985 PetscCall(DMGetDimension(rdm, &dim)); 8986 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8987 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8988 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8989 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8990 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8991 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8992 PetscCall(PetscFEDestroy(&fe)); 8993 PetscCall(DMCreateDS(rdm)); 8994 PetscCall(DMCreateGlobalVector(rdm, val)); 8995 PetscCall(DMCreateLocalVector(rdm, &lval)); 8996 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8997 PetscCall(DMGetLocalSection(rdm, §ion)); 8998 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8999 PetscCall(VecGetArray(lval, &v)); 9000 for (p = pStart; p < pEnd; ++p) { 9001 PetscInt cval, dof, off; 9002 9003 PetscCall(PetscSectionGetDof(section, p, &dof)); 9004 if (!dof) continue; 9005 PetscCall(DMLabelGetValue(label, p, &cval)); 9006 PetscCall(PetscSectionGetOffset(section, p, &off)); 9007 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9008 } 9009 PetscCall(VecRestoreArray(lval, &v)); 9010 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9011 PetscCall(VecDestroy(&lval)); 9012 PetscCall(DMDestroy(&rdm)); 9013 PetscFunctionReturn(PETSC_SUCCESS); 9014 } 9015 9016 /*@ 9017 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9018 9019 Input Parameter: 9020 . dm - The `DMPLEX` object 9021 9022 Level: developer 9023 9024 Notes: 9025 This is a useful diagnostic when creating meshes programmatically. 9026 9027 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9028 9029 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9030 @*/ 9031 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9032 { 9033 PetscSection coneSection, supportSection; 9034 const PetscInt *cone, *support; 9035 PetscInt coneSize, c, supportSize, s; 9036 PetscInt pStart, pEnd, p, pp, csize, ssize; 9037 PetscBool storagecheck = PETSC_TRUE; 9038 9039 PetscFunctionBegin; 9040 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9041 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9042 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9043 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9044 /* Check that point p is found in the support of its cone points, and vice versa */ 9045 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9046 for (p = pStart; p < pEnd; ++p) { 9047 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9048 PetscCall(DMPlexGetCone(dm, p, &cone)); 9049 for (c = 0; c < coneSize; ++c) { 9050 PetscBool dup = PETSC_FALSE; 9051 PetscInt d; 9052 for (d = c - 1; d >= 0; --d) { 9053 if (cone[c] == cone[d]) { 9054 dup = PETSC_TRUE; 9055 break; 9056 } 9057 } 9058 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9059 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9060 for (s = 0; s < supportSize; ++s) { 9061 if (support[s] == p) break; 9062 } 9063 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9064 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9065 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9066 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9067 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9068 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9069 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9070 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]); 9071 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9072 } 9073 } 9074 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9075 if (p != pp) { 9076 storagecheck = PETSC_FALSE; 9077 continue; 9078 } 9079 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9080 PetscCall(DMPlexGetSupport(dm, p, &support)); 9081 for (s = 0; s < supportSize; ++s) { 9082 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9083 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9084 for (c = 0; c < coneSize; ++c) { 9085 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9086 if (cone[c] != pp) { 9087 c = 0; 9088 break; 9089 } 9090 if (cone[c] == p) break; 9091 } 9092 if (c >= coneSize) { 9093 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9094 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9095 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9096 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9097 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9098 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9099 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9100 } 9101 } 9102 } 9103 if (storagecheck) { 9104 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9105 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9106 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9107 } 9108 PetscFunctionReturn(PETSC_SUCCESS); 9109 } 9110 9111 /* 9112 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. 9113 */ 9114 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9115 { 9116 DMPolytopeType cct; 9117 PetscInt ptpoints[4]; 9118 const PetscInt *cone, *ccone, *ptcone; 9119 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9120 9121 PetscFunctionBegin; 9122 *unsplit = 0; 9123 switch (ct) { 9124 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9125 ptpoints[npt++] = c; 9126 break; 9127 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9128 PetscCall(DMPlexGetCone(dm, c, &cone)); 9129 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9130 for (cp = 0; cp < coneSize; ++cp) { 9131 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9132 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9133 } 9134 break; 9135 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9136 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9137 PetscCall(DMPlexGetCone(dm, c, &cone)); 9138 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9139 for (cp = 0; cp < coneSize; ++cp) { 9140 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9141 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9142 for (ccp = 0; ccp < cconeSize; ++ccp) { 9143 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9144 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9145 PetscInt p; 9146 for (p = 0; p < npt; ++p) 9147 if (ptpoints[p] == ccone[ccp]) break; 9148 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9149 } 9150 } 9151 } 9152 break; 9153 default: 9154 break; 9155 } 9156 for (pt = 0; pt < npt; ++pt) { 9157 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9158 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9159 } 9160 PetscFunctionReturn(PETSC_SUCCESS); 9161 } 9162 9163 /*@ 9164 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9165 9166 Input Parameters: 9167 + dm - The `DMPLEX` object 9168 - cellHeight - Normally 0 9169 9170 Level: developer 9171 9172 Notes: 9173 This is a useful diagnostic when creating meshes programmatically. 9174 Currently applicable only to homogeneous simplex or tensor meshes. 9175 9176 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9177 9178 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9179 @*/ 9180 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9181 { 9182 DMPlexInterpolatedFlag interp; 9183 DMPolytopeType ct; 9184 PetscInt vStart, vEnd, cStart, cEnd, c; 9185 9186 PetscFunctionBegin; 9187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9188 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9189 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9190 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9191 for (c = cStart; c < cEnd; ++c) { 9192 PetscInt *closure = NULL; 9193 PetscInt coneSize, closureSize, cl, Nv = 0; 9194 9195 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9196 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9197 if (interp == DMPLEX_INTERPOLATED_FULL) { 9198 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9199 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)); 9200 } 9201 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9202 for (cl = 0; cl < closureSize * 2; cl += 2) { 9203 const PetscInt p = closure[cl]; 9204 if ((p >= vStart) && (p < vEnd)) ++Nv; 9205 } 9206 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9207 /* Special Case: Tensor faces with identified vertices */ 9208 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9209 PetscInt unsplit; 9210 9211 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9212 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9213 } 9214 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)); 9215 } 9216 PetscFunctionReturn(PETSC_SUCCESS); 9217 } 9218 9219 /*@ 9220 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9221 9222 Collective 9223 9224 Input Parameters: 9225 + dm - The `DMPLEX` object 9226 - cellHeight - Normally 0 9227 9228 Level: developer 9229 9230 Notes: 9231 This is a useful diagnostic when creating meshes programmatically. 9232 This routine is only relevant for meshes that are fully interpolated across all ranks. 9233 It will error out if a partially interpolated mesh is given on some rank. 9234 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9235 9236 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9237 9238 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9239 @*/ 9240 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9241 { 9242 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9243 DMPlexInterpolatedFlag interpEnum; 9244 9245 PetscFunctionBegin; 9246 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9247 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9248 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9249 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9250 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9251 PetscFunctionReturn(PETSC_SUCCESS); 9252 } 9253 9254 PetscCall(DMGetDimension(dm, &dim)); 9255 PetscCall(DMPlexGetDepth(dm, &depth)); 9256 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9257 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9258 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9259 for (c = cStart; c < cEnd; ++c) { 9260 const PetscInt *cone, *ornt, *faceSizes, *faces; 9261 const DMPolytopeType *faceTypes; 9262 DMPolytopeType ct; 9263 PetscInt numFaces, coneSize, f; 9264 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9265 9266 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9267 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9268 if (unsplit) continue; 9269 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9270 PetscCall(DMPlexGetCone(dm, c, &cone)); 9271 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9272 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9273 for (cl = 0; cl < closureSize * 2; cl += 2) { 9274 const PetscInt p = closure[cl]; 9275 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9276 } 9277 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9278 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); 9279 for (f = 0; f < numFaces; ++f) { 9280 DMPolytopeType fct; 9281 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9282 9283 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9284 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9285 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9286 const PetscInt p = fclosure[cl]; 9287 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9288 } 9289 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]); 9290 for (v = 0; v < fnumCorners; ++v) { 9291 if (fclosure[v] != faces[fOff + v]) { 9292 PetscInt v1; 9293 9294 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9295 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9296 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9297 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9298 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9299 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]); 9300 } 9301 } 9302 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9303 fOff += faceSizes[f]; 9304 } 9305 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9306 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9307 } 9308 } 9309 PetscFunctionReturn(PETSC_SUCCESS); 9310 } 9311 9312 /*@ 9313 DMPlexCheckGeometry - Check the geometry of mesh cells 9314 9315 Input Parameter: 9316 . dm - The `DMPLEX` object 9317 9318 Level: developer 9319 9320 Notes: 9321 This is a useful diagnostic when creating meshes programmatically. 9322 9323 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9324 9325 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9326 @*/ 9327 PetscErrorCode DMPlexCheckGeometry(DM dm) 9328 { 9329 Vec coordinates; 9330 PetscReal detJ, J[9], refVol = 1.0; 9331 PetscReal vol; 9332 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9333 9334 PetscFunctionBegin; 9335 PetscCall(DMGetDimension(dm, &dim)); 9336 PetscCall(DMGetCoordinateDim(dm, &dE)); 9337 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9338 PetscCall(DMPlexGetDepth(dm, &depth)); 9339 for (d = 0; d < dim; ++d) refVol *= 2.0; 9340 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9341 /* Make sure local coordinates are created, because that step is collective */ 9342 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9343 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9344 for (c = cStart; c < cEnd; ++c) { 9345 DMPolytopeType ct; 9346 PetscInt unsplit; 9347 PetscBool ignoreZeroVol = PETSC_FALSE; 9348 9349 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9350 switch (ct) { 9351 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9352 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9353 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9354 ignoreZeroVol = PETSC_TRUE; 9355 break; 9356 default: 9357 break; 9358 } 9359 switch (ct) { 9360 case DM_POLYTOPE_TRI_PRISM: 9361 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9362 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9363 case DM_POLYTOPE_PYRAMID: 9364 continue; 9365 default: 9366 break; 9367 } 9368 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9369 if (unsplit) continue; 9370 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9371 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); 9372 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9373 /* This should work with periodicity since DG coordinates should be used */ 9374 if (depth > 1) { 9375 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9376 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); 9377 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9378 } 9379 } 9380 PetscFunctionReturn(PETSC_SUCCESS); 9381 } 9382 9383 /*@ 9384 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9385 9386 Collective 9387 9388 Input Parameters: 9389 + dm - The `DMPLEX` object 9390 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9391 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9392 9393 Level: developer 9394 9395 Notes: 9396 This is mainly intended for debugging/testing purposes. 9397 9398 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9399 9400 Extra roots can come from periodic cuts, where additional points appear on the boundary 9401 9402 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9403 @*/ 9404 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9405 { 9406 PetscInt l, nleaves, nroots, overlap; 9407 const PetscInt *locals; 9408 const PetscSFNode *remotes; 9409 PetscBool distributed; 9410 MPI_Comm comm; 9411 PetscMPIInt rank; 9412 9413 PetscFunctionBegin; 9414 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9415 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9416 else pointSF = dm->sf; 9417 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9418 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9419 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9420 { 9421 PetscMPIInt mpiFlag; 9422 9423 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9424 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9425 } 9426 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9427 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9428 if (!distributed) { 9429 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); 9430 PetscFunctionReturn(PETSC_SUCCESS); 9431 } 9432 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); 9433 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9434 9435 /* Check SF graph is compatible with DMPlex chart */ 9436 { 9437 PetscInt pStart, pEnd, maxLeaf; 9438 9439 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9440 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9441 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9442 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9443 } 9444 9445 /* Check Point SF has no local points referenced */ 9446 for (l = 0; l < nleaves; l++) { 9447 PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%d,%" PetscInt_FMT ")", locals ? locals[l] : l, (PetscMPIInt)remotes[l].rank, remotes[l].index); 9448 } 9449 9450 /* Check there are no cells in interface */ 9451 if (!overlap) { 9452 PetscInt cellHeight, cStart, cEnd; 9453 9454 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9455 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9456 for (l = 0; l < nleaves; ++l) { 9457 const PetscInt point = locals ? locals[l] : l; 9458 9459 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9460 } 9461 } 9462 9463 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9464 { 9465 const PetscInt *rootdegree; 9466 9467 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9468 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9469 for (l = 0; l < nleaves; ++l) { 9470 const PetscInt point = locals ? locals[l] : l; 9471 const PetscInt *cone; 9472 PetscInt coneSize, c, idx; 9473 9474 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9475 PetscCall(DMPlexGetCone(dm, point, &cone)); 9476 for (c = 0; c < coneSize; ++c) { 9477 if (!rootdegree[cone[c]]) { 9478 if (locals) { 9479 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9480 } else { 9481 idx = (cone[c] < nleaves) ? cone[c] : -1; 9482 } 9483 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9484 } 9485 } 9486 } 9487 } 9488 PetscFunctionReturn(PETSC_SUCCESS); 9489 } 9490 9491 /*@ 9492 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9493 9494 Collective 9495 9496 Input Parameter: 9497 . dm - The `DMPLEX` object 9498 9499 Level: developer 9500 9501 Notes: 9502 This is mainly intended for debugging/testing purposes. 9503 9504 Other cell types which are disconnected would be caught by the symmetry and face checks. 9505 9506 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9507 9508 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9509 @*/ 9510 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9511 { 9512 PetscInt pStart, pEnd, vStart, vEnd; 9513 9514 PetscFunctionBegin; 9515 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9516 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9517 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9518 for (PetscInt v = vStart; v < vEnd; ++v) { 9519 PetscInt suppSize; 9520 9521 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9522 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9523 } 9524 PetscFunctionReturn(PETSC_SUCCESS); 9525 } 9526 9527 /*@ 9528 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9529 9530 Input Parameter: 9531 . dm - The `DMPLEX` object 9532 9533 Level: developer 9534 9535 Notes: 9536 This is a useful diagnostic when creating meshes programmatically. 9537 9538 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9539 9540 Currently does not include `DMPlexCheckCellShape()`. 9541 9542 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9543 @*/ 9544 PetscErrorCode DMPlexCheck(DM dm) 9545 { 9546 PetscInt cellHeight; 9547 9548 PetscFunctionBegin; 9549 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9550 PetscCall(DMPlexCheckSymmetry(dm)); 9551 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9552 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9553 PetscCall(DMPlexCheckGeometry(dm)); 9554 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9555 PetscCall(DMPlexCheckInterfaceCones(dm)); 9556 PetscCall(DMPlexCheckOrphanVertices(dm)); 9557 PetscFunctionReturn(PETSC_SUCCESS); 9558 } 9559 9560 typedef struct cell_stats { 9561 PetscReal min, max, sum, squaresum; 9562 PetscInt count; 9563 } cell_stats_t; 9564 9565 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9566 { 9567 PetscInt i, N = *len; 9568 9569 for (i = 0; i < N; i++) { 9570 cell_stats_t *A = (cell_stats_t *)a; 9571 cell_stats_t *B = (cell_stats_t *)b; 9572 9573 B->min = PetscMin(A->min, B->min); 9574 B->max = PetscMax(A->max, B->max); 9575 B->sum += A->sum; 9576 B->squaresum += A->squaresum; 9577 B->count += A->count; 9578 } 9579 } 9580 9581 /*@ 9582 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9583 9584 Collective 9585 9586 Input Parameters: 9587 + dm - The `DMPLEX` object 9588 . output - If true, statistics will be displayed on `stdout` 9589 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9590 9591 Level: developer 9592 9593 Notes: 9594 This is mainly intended for debugging/testing purposes. 9595 9596 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9597 9598 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9599 @*/ 9600 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9601 { 9602 DM dmCoarse; 9603 cell_stats_t stats, globalStats; 9604 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9605 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9606 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9607 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9608 PetscMPIInt rank, size; 9609 9610 PetscFunctionBegin; 9611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9612 stats.min = PETSC_MAX_REAL; 9613 stats.max = PETSC_MIN_REAL; 9614 stats.sum = stats.squaresum = 0.; 9615 stats.count = 0; 9616 9617 PetscCallMPI(MPI_Comm_size(comm, &size)); 9618 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9619 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9620 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9621 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9622 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9623 for (c = cStart; c < cEnd; c++) { 9624 PetscInt i; 9625 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9626 9627 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9628 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9629 for (i = 0; i < PetscSqr(cdim); ++i) { 9630 frobJ += J[i] * J[i]; 9631 frobInvJ += invJ[i] * invJ[i]; 9632 } 9633 cond2 = frobJ * frobInvJ; 9634 cond = PetscSqrtReal(cond2); 9635 9636 stats.min = PetscMin(stats.min, cond); 9637 stats.max = PetscMax(stats.max, cond); 9638 stats.sum += cond; 9639 stats.squaresum += cond2; 9640 stats.count++; 9641 if (output && cond > limit) { 9642 PetscSection coordSection; 9643 Vec coordsLocal; 9644 PetscScalar *coords = NULL; 9645 PetscInt Nv, d, clSize, cl, *closure = NULL; 9646 9647 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9648 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9649 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9650 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9651 for (i = 0; i < Nv / cdim; ++i) { 9652 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9653 for (d = 0; d < cdim; ++d) { 9654 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9655 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9656 } 9657 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9658 } 9659 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9660 for (cl = 0; cl < clSize * 2; cl += 2) { 9661 const PetscInt edge = closure[cl]; 9662 9663 if ((edge >= eStart) && (edge < eEnd)) { 9664 PetscReal len; 9665 9666 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9667 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9668 } 9669 } 9670 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9671 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9672 } 9673 } 9674 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9675 9676 if (size > 1) { 9677 PetscMPIInt blockLengths[2] = {4, 1}; 9678 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9679 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9680 MPI_Op statReduce; 9681 9682 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9683 PetscCallMPI(MPI_Type_commit(&statType)); 9684 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9685 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9686 PetscCallMPI(MPI_Op_free(&statReduce)); 9687 PetscCallMPI(MPI_Type_free(&statType)); 9688 } else { 9689 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9690 } 9691 if (rank == 0) { 9692 count = globalStats.count; 9693 min = globalStats.min; 9694 max = globalStats.max; 9695 mean = globalStats.sum / globalStats.count; 9696 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9697 } 9698 9699 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)); 9700 PetscCall(PetscFree2(J, invJ)); 9701 9702 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9703 if (dmCoarse) { 9704 PetscBool isplex; 9705 9706 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9707 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9708 } 9709 PetscFunctionReturn(PETSC_SUCCESS); 9710 } 9711 9712 /*@ 9713 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9714 orthogonal quality below given tolerance. 9715 9716 Collective 9717 9718 Input Parameters: 9719 + dm - The `DMPLEX` object 9720 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9721 - atol - [0, 1] Absolute tolerance for tagging cells. 9722 9723 Output Parameters: 9724 + OrthQual - `Vec` containing orthogonal quality per cell 9725 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9726 9727 Options Database Keys: 9728 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9729 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9730 9731 Level: intermediate 9732 9733 Notes: 9734 Orthogonal quality is given by the following formula\: 9735 9736 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9737 9738 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 9739 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9740 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9741 calculating the cosine of the angle between these vectors. 9742 9743 Orthogonal quality ranges from 1 (best) to 0 (worst). 9744 9745 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9746 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9747 9748 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9749 9750 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9751 @*/ 9752 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9753 { 9754 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9755 PetscInt *idx; 9756 PetscScalar *oqVals; 9757 const PetscScalar *cellGeomArr, *faceGeomArr; 9758 PetscReal *ci, *fi, *Ai; 9759 MPI_Comm comm; 9760 Vec cellgeom, facegeom; 9761 DM dmFace, dmCell; 9762 IS glob; 9763 ISLocalToGlobalMapping ltog; 9764 PetscViewer vwr; 9765 9766 PetscFunctionBegin; 9767 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9768 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9769 PetscAssertPointer(OrthQual, 4); 9770 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9771 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9772 PetscCall(DMGetDimension(dm, &nc)); 9773 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9774 { 9775 DMPlexInterpolatedFlag interpFlag; 9776 9777 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9778 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9779 PetscMPIInt rank; 9780 9781 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9782 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9783 } 9784 } 9785 if (OrthQualLabel) { 9786 PetscAssertPointer(OrthQualLabel, 5); 9787 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9788 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9789 } else { 9790 *OrthQualLabel = NULL; 9791 } 9792 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9793 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9794 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9795 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9796 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9797 PetscCall(VecCreate(comm, OrthQual)); 9798 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9799 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9800 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9801 PetscCall(VecSetUp(*OrthQual)); 9802 PetscCall(ISDestroy(&glob)); 9803 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9804 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9805 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9806 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9807 PetscCall(VecGetDM(cellgeom, &dmCell)); 9808 PetscCall(VecGetDM(facegeom, &dmFace)); 9809 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9810 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9811 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9812 PetscInt cellarr[2], *adj = NULL; 9813 PetscScalar *cArr, *fArr; 9814 PetscReal minvalc = 1.0, minvalf = 1.0; 9815 PetscFVCellGeom *cg; 9816 9817 idx[cellIter] = cell - cStart; 9818 cellarr[0] = cell; 9819 /* Make indexing into cellGeom easier */ 9820 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9821 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9822 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9823 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9824 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9825 PetscInt i; 9826 const PetscInt neigh = adj[cellneigh]; 9827 PetscReal normci = 0, normfi = 0, normai = 0; 9828 PetscFVCellGeom *cgneigh; 9829 PetscFVFaceGeom *fg; 9830 9831 /* Don't count ourselves in the neighbor list */ 9832 if (neigh == cell) continue; 9833 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9834 cellarr[1] = neigh; 9835 { 9836 PetscInt numcovpts; 9837 const PetscInt *covpts; 9838 9839 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9840 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9841 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9842 } 9843 9844 /* Compute c_i, f_i and their norms */ 9845 for (i = 0; i < nc; i++) { 9846 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9847 fi[i] = fg->centroid[i] - cg->centroid[i]; 9848 Ai[i] = fg->normal[i]; 9849 normci += PetscPowReal(ci[i], 2); 9850 normfi += PetscPowReal(fi[i], 2); 9851 normai += PetscPowReal(Ai[i], 2); 9852 } 9853 normci = PetscSqrtReal(normci); 9854 normfi = PetscSqrtReal(normfi); 9855 normai = PetscSqrtReal(normai); 9856 9857 /* Normalize and compute for each face-cell-normal pair */ 9858 for (i = 0; i < nc; i++) { 9859 ci[i] = ci[i] / normci; 9860 fi[i] = fi[i] / normfi; 9861 Ai[i] = Ai[i] / normai; 9862 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9863 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9864 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9865 } 9866 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9867 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9868 } 9869 PetscCall(PetscFree(adj)); 9870 PetscCall(PetscFree2(cArr, fArr)); 9871 /* Defer to cell if they're equal */ 9872 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9873 if (OrthQualLabel) { 9874 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9875 } 9876 } 9877 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9878 PetscCall(VecAssemblyBegin(*OrthQual)); 9879 PetscCall(VecAssemblyEnd(*OrthQual)); 9880 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9881 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9882 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9883 if (OrthQualLabel) { 9884 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9885 } 9886 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9887 PetscCall(PetscViewerDestroy(&vwr)); 9888 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9889 PetscFunctionReturn(PETSC_SUCCESS); 9890 } 9891 9892 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9893 * interpolator construction */ 9894 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9895 { 9896 PetscSection section, newSection, gsection; 9897 PetscSF sf; 9898 PetscBool hasConstraints, ghasConstraints; 9899 9900 PetscFunctionBegin; 9901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9902 PetscAssertPointer(odm, 2); 9903 PetscCall(DMGetLocalSection(dm, §ion)); 9904 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9905 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9906 if (!ghasConstraints) { 9907 PetscCall(PetscObjectReference((PetscObject)dm)); 9908 *odm = dm; 9909 PetscFunctionReturn(PETSC_SUCCESS); 9910 } 9911 PetscCall(DMClone(dm, odm)); 9912 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 9913 PetscCall(DMGetLocalSection(*odm, &newSection)); 9914 PetscCall(DMGetPointSF(*odm, &sf)); 9915 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9916 PetscCall(DMSetGlobalSection(*odm, gsection)); 9917 PetscCall(PetscSectionDestroy(&gsection)); 9918 PetscFunctionReturn(PETSC_SUCCESS); 9919 } 9920 9921 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9922 { 9923 DM dmco, dmfo; 9924 Mat interpo; 9925 Vec rscale; 9926 Vec cglobalo, clocal; 9927 Vec fglobal, fglobalo, flocal; 9928 PetscBool regular; 9929 9930 PetscFunctionBegin; 9931 PetscCall(DMGetFullDM(dmc, &dmco)); 9932 PetscCall(DMGetFullDM(dmf, &dmfo)); 9933 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9934 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9935 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9936 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9937 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9938 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9939 PetscCall(VecSet(cglobalo, 0.)); 9940 PetscCall(VecSet(clocal, 0.)); 9941 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9942 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9943 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9944 PetscCall(VecSet(fglobal, 0.)); 9945 PetscCall(VecSet(fglobalo, 0.)); 9946 PetscCall(VecSet(flocal, 0.)); 9947 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9948 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9949 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9950 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9951 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9952 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9953 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9954 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9955 *shift = fglobal; 9956 PetscCall(VecDestroy(&flocal)); 9957 PetscCall(VecDestroy(&fglobalo)); 9958 PetscCall(VecDestroy(&clocal)); 9959 PetscCall(VecDestroy(&cglobalo)); 9960 PetscCall(VecDestroy(&rscale)); 9961 PetscCall(MatDestroy(&interpo)); 9962 PetscCall(DMDestroy(&dmfo)); 9963 PetscCall(DMDestroy(&dmco)); 9964 PetscFunctionReturn(PETSC_SUCCESS); 9965 } 9966 9967 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9968 { 9969 PetscObject shifto; 9970 Vec shift; 9971 9972 PetscFunctionBegin; 9973 if (!interp) { 9974 Vec rscale; 9975 9976 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9977 PetscCall(VecDestroy(&rscale)); 9978 } else { 9979 PetscCall(PetscObjectReference((PetscObject)interp)); 9980 } 9981 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9982 if (!shifto) { 9983 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9984 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9985 shifto = (PetscObject)shift; 9986 PetscCall(VecDestroy(&shift)); 9987 } 9988 shift = (Vec)shifto; 9989 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9990 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9991 PetscCall(MatDestroy(&interp)); 9992 PetscFunctionReturn(PETSC_SUCCESS); 9993 } 9994 9995 /* Pointwise interpolation 9996 Just code FEM for now 9997 u^f = I u^c 9998 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9999 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10000 I_{ij} = psi^f_i phi^c_j 10001 */ 10002 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10003 { 10004 PetscSection gsc, gsf; 10005 PetscInt m, n; 10006 void *ctx; 10007 DM cdm; 10008 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10009 10010 PetscFunctionBegin; 10011 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10012 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10013 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10014 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10015 10016 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10017 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10018 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10019 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10020 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10021 10022 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10023 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10024 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10025 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10026 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10027 if (scaling) { 10028 /* Use naive scaling */ 10029 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10030 } 10031 PetscFunctionReturn(PETSC_SUCCESS); 10032 } 10033 10034 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10035 { 10036 VecScatter ctx; 10037 10038 PetscFunctionBegin; 10039 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10040 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10041 PetscCall(VecScatterDestroy(&ctx)); 10042 PetscFunctionReturn(PETSC_SUCCESS); 10043 } 10044 10045 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[]) 10046 { 10047 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10048 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10049 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10050 } 10051 10052 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10053 { 10054 DM dmc; 10055 PetscDS ds; 10056 Vec ones, locmass; 10057 IS cellIS; 10058 PetscFormKey key; 10059 PetscInt depth; 10060 10061 PetscFunctionBegin; 10062 PetscCall(DMClone(dm, &dmc)); 10063 PetscCall(DMCopyDisc(dm, dmc)); 10064 PetscCall(DMGetDS(dmc, &ds)); 10065 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10066 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10067 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10068 else PetscCall(DMGetLocalVector(dm, &locmass)); 10069 PetscCall(DMGetLocalVector(dm, &ones)); 10070 PetscCall(DMPlexGetDepth(dm, &depth)); 10071 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10072 PetscCall(VecSet(locmass, 0.0)); 10073 PetscCall(VecSet(ones, 1.0)); 10074 key.label = NULL; 10075 key.value = 0; 10076 key.field = 0; 10077 key.part = 0; 10078 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10079 PetscCall(ISDestroy(&cellIS)); 10080 if (mass) { 10081 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10082 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10083 } 10084 PetscCall(DMRestoreLocalVector(dm, &ones)); 10085 if (lmass) *lmass = locmass; 10086 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10087 PetscCall(DMDestroy(&dmc)); 10088 PetscFunctionReturn(PETSC_SUCCESS); 10089 } 10090 10091 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10092 { 10093 PetscSection gsc, gsf; 10094 PetscInt m, n; 10095 void *ctx; 10096 DM cdm; 10097 PetscBool regular; 10098 10099 PetscFunctionBegin; 10100 if (dmFine == dmCoarse) { 10101 DM dmc; 10102 PetscDS ds; 10103 PetscWeakForm wf; 10104 Vec u; 10105 IS cellIS; 10106 PetscFormKey key; 10107 PetscInt depth; 10108 10109 PetscCall(DMClone(dmFine, &dmc)); 10110 PetscCall(DMCopyDisc(dmFine, dmc)); 10111 PetscCall(DMGetDS(dmc, &ds)); 10112 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10113 PetscCall(PetscWeakFormClear(wf)); 10114 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10115 PetscCall(DMCreateMatrix(dmc, mass)); 10116 PetscCall(DMGetLocalVector(dmc, &u)); 10117 PetscCall(DMPlexGetDepth(dmc, &depth)); 10118 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10119 PetscCall(MatZeroEntries(*mass)); 10120 key.label = NULL; 10121 key.value = 0; 10122 key.field = 0; 10123 key.part = 0; 10124 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10125 PetscCall(ISDestroy(&cellIS)); 10126 PetscCall(DMRestoreLocalVector(dmc, &u)); 10127 PetscCall(DMDestroy(&dmc)); 10128 } else { 10129 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10130 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10131 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10132 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10133 10134 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10135 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10136 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10137 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10138 10139 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10140 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10141 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10142 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10143 } 10144 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10145 PetscFunctionReturn(PETSC_SUCCESS); 10146 } 10147 10148 /*@ 10149 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10150 10151 Input Parameter: 10152 . dm - The `DMPLEX` object 10153 10154 Output Parameter: 10155 . regular - The flag 10156 10157 Level: intermediate 10158 10159 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10160 @*/ 10161 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10162 { 10163 PetscFunctionBegin; 10164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10165 PetscAssertPointer(regular, 2); 10166 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10167 PetscFunctionReturn(PETSC_SUCCESS); 10168 } 10169 10170 /*@ 10171 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10172 10173 Input Parameters: 10174 + dm - The `DMPLEX` object 10175 - regular - The flag 10176 10177 Level: intermediate 10178 10179 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10180 @*/ 10181 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10182 { 10183 PetscFunctionBegin; 10184 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10185 ((DM_Plex *)dm->data)->regularRefinement = regular; 10186 PetscFunctionReturn(PETSC_SUCCESS); 10187 } 10188 10189 /*@ 10190 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10191 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10192 10193 Not Collective 10194 10195 Input Parameter: 10196 . dm - The `DMPLEX` object 10197 10198 Output Parameters: 10199 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10200 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10201 10202 Level: intermediate 10203 10204 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10205 @*/ 10206 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10207 { 10208 DM_Plex *plex = (DM_Plex *)dm->data; 10209 10210 PetscFunctionBegin; 10211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10212 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10213 if (anchorSection) *anchorSection = plex->anchorSection; 10214 if (anchorIS) *anchorIS = plex->anchorIS; 10215 PetscFunctionReturn(PETSC_SUCCESS); 10216 } 10217 10218 /*@ 10219 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10220 10221 Collective 10222 10223 Input Parameters: 10224 + dm - The `DMPLEX` object 10225 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10226 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10227 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10228 10229 Level: intermediate 10230 10231 Notes: 10232 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10233 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10234 combination of other points' degrees of freedom. 10235 10236 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10237 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10238 10239 The reference counts of `anchorSection` and `anchorIS` are incremented. 10240 10241 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10242 @*/ 10243 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10244 { 10245 DM_Plex *plex = (DM_Plex *)dm->data; 10246 PetscMPIInt result; 10247 10248 PetscFunctionBegin; 10249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10250 if (anchorSection) { 10251 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10252 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10253 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10254 } 10255 if (anchorIS) { 10256 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10257 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10258 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10259 } 10260 10261 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10262 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10263 plex->anchorSection = anchorSection; 10264 10265 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10266 PetscCall(ISDestroy(&plex->anchorIS)); 10267 plex->anchorIS = anchorIS; 10268 10269 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10270 PetscInt size, a, pStart, pEnd; 10271 const PetscInt *anchors; 10272 10273 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10274 PetscCall(ISGetLocalSize(anchorIS, &size)); 10275 PetscCall(ISGetIndices(anchorIS, &anchors)); 10276 for (a = 0; a < size; a++) { 10277 PetscInt p; 10278 10279 p = anchors[a]; 10280 if (p >= pStart && p < pEnd) { 10281 PetscInt dof; 10282 10283 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10284 if (dof) { 10285 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10286 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10287 } 10288 } 10289 } 10290 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10291 } 10292 /* reset the generic constraints */ 10293 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10294 PetscFunctionReturn(PETSC_SUCCESS); 10295 } 10296 10297 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10298 { 10299 PetscSection anchorSection; 10300 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10301 10302 PetscFunctionBegin; 10303 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10304 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10305 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10306 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10307 if (numFields) { 10308 PetscInt f; 10309 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10310 10311 for (f = 0; f < numFields; f++) { 10312 PetscInt numComp; 10313 10314 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10315 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10316 } 10317 } 10318 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10319 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10320 pStart = PetscMax(pStart, sStart); 10321 pEnd = PetscMin(pEnd, sEnd); 10322 pEnd = PetscMax(pStart, pEnd); 10323 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10324 for (p = pStart; p < pEnd; p++) { 10325 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10326 if (dof) { 10327 PetscCall(PetscSectionGetDof(section, p, &dof)); 10328 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10329 for (f = 0; f < numFields; f++) { 10330 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10331 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10332 } 10333 } 10334 } 10335 PetscCall(PetscSectionSetUp(*cSec)); 10336 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10337 PetscFunctionReturn(PETSC_SUCCESS); 10338 } 10339 10340 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10341 { 10342 PetscSection aSec; 10343 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10344 const PetscInt *anchors; 10345 PetscInt numFields, f; 10346 IS aIS; 10347 MatType mtype; 10348 PetscBool iscuda, iskokkos; 10349 10350 PetscFunctionBegin; 10351 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10352 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10353 PetscCall(PetscSectionGetStorageSize(section, &n)); 10354 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10355 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10356 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10357 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10358 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10359 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10360 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10361 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10362 else mtype = MATSEQAIJ; 10363 PetscCall(MatSetType(*cMat, mtype)); 10364 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10365 PetscCall(ISGetIndices(aIS, &anchors)); 10366 /* cSec will be a subset of aSec and section */ 10367 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10368 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10369 PetscCall(PetscMalloc1(m + 1, &i)); 10370 i[0] = 0; 10371 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10372 for (p = pStart; p < pEnd; p++) { 10373 PetscInt rDof, rOff, r; 10374 10375 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10376 if (!rDof) continue; 10377 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10378 if (numFields) { 10379 for (f = 0; f < numFields; f++) { 10380 annz = 0; 10381 for (r = 0; r < rDof; r++) { 10382 a = anchors[rOff + r]; 10383 if (a < sStart || a >= sEnd) continue; 10384 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10385 annz += aDof; 10386 } 10387 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10388 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10389 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10390 } 10391 } else { 10392 annz = 0; 10393 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10394 for (q = 0; q < dof; q++) { 10395 a = anchors[rOff + q]; 10396 if (a < sStart || a >= sEnd) continue; 10397 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10398 annz += aDof; 10399 } 10400 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10401 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10402 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10403 } 10404 } 10405 nnz = i[m]; 10406 PetscCall(PetscMalloc1(nnz, &j)); 10407 offset = 0; 10408 for (p = pStart; p < pEnd; p++) { 10409 if (numFields) { 10410 for (f = 0; f < numFields; f++) { 10411 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10412 for (q = 0; q < dof; q++) { 10413 PetscInt rDof, rOff, r; 10414 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10415 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10416 for (r = 0; r < rDof; r++) { 10417 PetscInt s; 10418 10419 a = anchors[rOff + r]; 10420 if (a < sStart || a >= sEnd) continue; 10421 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10422 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10423 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10424 } 10425 } 10426 } 10427 } else { 10428 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10429 for (q = 0; q < dof; q++) { 10430 PetscInt rDof, rOff, r; 10431 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10432 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10433 for (r = 0; r < rDof; r++) { 10434 PetscInt s; 10435 10436 a = anchors[rOff + r]; 10437 if (a < sStart || a >= sEnd) continue; 10438 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10439 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10440 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10441 } 10442 } 10443 } 10444 } 10445 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10446 PetscCall(PetscFree(i)); 10447 PetscCall(PetscFree(j)); 10448 PetscCall(ISRestoreIndices(aIS, &anchors)); 10449 PetscFunctionReturn(PETSC_SUCCESS); 10450 } 10451 10452 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10453 { 10454 DM_Plex *plex = (DM_Plex *)dm->data; 10455 PetscSection anchorSection, section, cSec; 10456 Mat cMat; 10457 10458 PetscFunctionBegin; 10459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10460 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10461 if (anchorSection) { 10462 PetscInt Nf; 10463 10464 PetscCall(DMGetLocalSection(dm, §ion)); 10465 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10466 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10467 PetscCall(DMGetNumFields(dm, &Nf)); 10468 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10469 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10470 PetscCall(PetscSectionDestroy(&cSec)); 10471 PetscCall(MatDestroy(&cMat)); 10472 } 10473 PetscFunctionReturn(PETSC_SUCCESS); 10474 } 10475 10476 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10477 { 10478 IS subis; 10479 PetscSection section, subsection; 10480 10481 PetscFunctionBegin; 10482 PetscCall(DMGetLocalSection(dm, §ion)); 10483 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10484 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10485 /* Create subdomain */ 10486 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10487 /* Create submodel */ 10488 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10489 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10490 PetscCall(DMSetLocalSection(*subdm, subsection)); 10491 PetscCall(PetscSectionDestroy(&subsection)); 10492 PetscCall(DMCopyDisc(dm, *subdm)); 10493 /* Create map from submodel to global model */ 10494 if (is) { 10495 PetscSection sectionGlobal, subsectionGlobal; 10496 IS spIS; 10497 const PetscInt *spmap; 10498 PetscInt *subIndices; 10499 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10500 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10501 10502 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10503 PetscCall(ISGetIndices(spIS, &spmap)); 10504 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10505 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10506 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10507 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10508 for (p = pStart; p < pEnd; ++p) { 10509 PetscInt gdof, pSubSize = 0; 10510 10511 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10512 if (gdof > 0) { 10513 for (f = 0; f < Nf; ++f) { 10514 PetscInt fdof, fcdof; 10515 10516 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10517 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10518 pSubSize += fdof - fcdof; 10519 } 10520 subSize += pSubSize; 10521 if (pSubSize) { 10522 if (bs < 0) { 10523 bs = pSubSize; 10524 } else if (bs != pSubSize) { 10525 /* Layout does not admit a pointwise block size */ 10526 bs = 1; 10527 } 10528 } 10529 } 10530 } 10531 /* Must have same blocksize on all procs (some might have no points) */ 10532 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10533 bsLocal[1] = bs; 10534 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10535 if (bsMinMax[0] != bsMinMax[1]) { 10536 bs = 1; 10537 } else { 10538 bs = bsMinMax[0]; 10539 } 10540 PetscCall(PetscMalloc1(subSize, &subIndices)); 10541 for (p = pStart; p < pEnd; ++p) { 10542 PetscInt gdof, goff; 10543 10544 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10545 if (gdof > 0) { 10546 const PetscInt point = spmap[p]; 10547 10548 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10549 for (f = 0; f < Nf; ++f) { 10550 PetscInt fdof, fcdof, fc, f2, poff = 0; 10551 10552 /* Can get rid of this loop by storing field information in the global section */ 10553 for (f2 = 0; f2 < f; ++f2) { 10554 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10555 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10556 poff += fdof - fcdof; 10557 } 10558 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10559 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10560 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10561 } 10562 } 10563 } 10564 PetscCall(ISRestoreIndices(spIS, &spmap)); 10565 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10566 if (bs > 1) { 10567 /* We need to check that the block size does not come from non-contiguous fields */ 10568 PetscInt i, j, set = 1; 10569 for (i = 0; i < subSize; i += bs) { 10570 for (j = 0; j < bs; ++j) { 10571 if (subIndices[i + j] != subIndices[i] + j) { 10572 set = 0; 10573 break; 10574 } 10575 } 10576 } 10577 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10578 } 10579 /* Attach nullspace */ 10580 for (f = 0; f < Nf; ++f) { 10581 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10582 if ((*subdm)->nullspaceConstructors[f]) break; 10583 } 10584 if (f < Nf) { 10585 MatNullSpace nullSpace; 10586 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10587 10588 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10589 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10590 } 10591 } 10592 PetscFunctionReturn(PETSC_SUCCESS); 10593 } 10594 10595 /*@ 10596 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10597 10598 Input Parameters: 10599 + dm - The `DM` 10600 - dummy - unused argument 10601 10602 Options Database Key: 10603 . -dm_plex_monitor_throughput - Activate the monitor 10604 10605 Level: developer 10606 10607 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10608 @*/ 10609 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10610 { 10611 PetscLogHandler default_handler; 10612 10613 PetscFunctionBegin; 10614 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10615 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10616 if (default_handler) { 10617 PetscLogEvent event; 10618 PetscEventPerfInfo eventInfo; 10619 PetscReal cellRate, flopRate; 10620 PetscInt cStart, cEnd, Nf, N; 10621 const char *name; 10622 10623 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10624 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10625 PetscCall(DMGetNumFields(dm, &Nf)); 10626 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10627 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10628 N = (cEnd - cStart) * Nf * eventInfo.count; 10629 flopRate = eventInfo.flops / eventInfo.time; 10630 cellRate = N / eventInfo.time; 10631 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))); 10632 } else { 10633 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."); 10634 } 10635 PetscFunctionReturn(PETSC_SUCCESS); 10636 } 10637