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 } else if (ishdf5) { 582 #if defined(PETSC_HAVE_HDF5) 583 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 584 #else 585 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 586 #endif 587 } else if (isexodusii) { 588 #if defined(PETSC_HAVE_EXODUSII) 589 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 590 #else 591 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 592 #endif 593 } else { 594 PetscBool isseq; 595 596 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 597 if (isseq) PetscCall(VecView_Seq(v, viewer)); 598 else PetscCall(VecView_MPI(v, viewer)); 599 } 600 PetscFunctionReturn(PETSC_SUCCESS); 601 } 602 603 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 604 { 605 DM dm; 606 MPI_Comm comm; 607 PetscViewerFormat format; 608 Vec v; 609 PetscBool isvtk, ishdf5; 610 611 PetscFunctionBegin; 612 PetscCall(VecGetDM(originalv, &dm)); 613 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 614 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 615 PetscCall(PetscViewerGetFormat(viewer, &format)); 616 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 617 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 618 if (format == PETSC_VIEWER_NATIVE) { 619 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 620 /* this need a better fix */ 621 if (dm->useNatural) { 622 if (dm->sfNatural) { 623 const char *vecname; 624 PetscInt n, nroots; 625 626 PetscCall(VecGetLocalSize(originalv, &n)); 627 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 628 if (n == nroots) { 629 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 630 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 631 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 632 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 633 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 634 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 635 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 636 } else v = originalv; 637 } else v = originalv; 638 639 if (ishdf5) { 640 #if defined(PETSC_HAVE_HDF5) 641 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 642 #else 643 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 644 #endif 645 } else if (isvtk) { 646 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 647 } else { 648 PetscBool isseq; 649 650 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 651 if (isseq) PetscCall(VecView_Seq(v, viewer)); 652 else PetscCall(VecView_MPI(v, viewer)); 653 } 654 if (v != originalv) PetscCall(VecDestroy(&v)); 655 PetscFunctionReturn(PETSC_SUCCESS); 656 } 657 658 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 659 { 660 DM dm; 661 PetscBool ishdf5; 662 663 PetscFunctionBegin; 664 PetscCall(VecGetDM(v, &dm)); 665 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 666 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 667 if (ishdf5) { 668 DM dmBC; 669 Vec gv; 670 const char *name; 671 672 PetscCall(DMGetOutputDM(dm, &dmBC)); 673 PetscCall(DMGetGlobalVector(dmBC, &gv)); 674 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 675 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 676 PetscCall(VecLoad_Default(gv, viewer)); 677 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 678 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 679 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 680 } else PetscCall(VecLoad_Default(v, viewer)); 681 PetscFunctionReturn(PETSC_SUCCESS); 682 } 683 684 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 685 { 686 DM dm; 687 PetscBool ishdf5, isexodusii, iscgns; 688 689 PetscFunctionBegin; 690 PetscCall(VecGetDM(v, &dm)); 691 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 692 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 693 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 694 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 695 if (ishdf5) { 696 #if defined(PETSC_HAVE_HDF5) 697 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 698 #else 699 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 700 #endif 701 } else if (isexodusii) { 702 #if defined(PETSC_HAVE_EXODUSII) 703 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 704 #else 705 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 706 #endif 707 } else if (iscgns) { 708 #if defined(PETSC_HAVE_CGNS) 709 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 710 #else 711 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 712 #endif 713 } else PetscCall(VecLoad_Default(v, viewer)); 714 PetscFunctionReturn(PETSC_SUCCESS); 715 } 716 717 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 718 { 719 DM dm; 720 PetscViewerFormat format; 721 PetscBool ishdf5; 722 723 PetscFunctionBegin; 724 PetscCall(VecGetDM(originalv, &dm)); 725 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 726 PetscCall(PetscViewerGetFormat(viewer, &format)); 727 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 728 if (format == PETSC_VIEWER_NATIVE) { 729 if (dm->useNatural) { 730 if (dm->sfNatural) { 731 if (ishdf5) { 732 #if defined(PETSC_HAVE_HDF5) 733 Vec v; 734 const char *vecname; 735 736 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 737 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 738 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 739 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 740 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 741 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 742 PetscCall(VecDestroy(&v)); 743 #else 744 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 745 #endif 746 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 747 } 748 } else PetscCall(VecLoad_Default(originalv, viewer)); 749 } 750 PetscFunctionReturn(PETSC_SUCCESS); 751 } 752 753 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 754 { 755 PetscSection coordSection; 756 Vec coordinates; 757 DMLabel depthLabel, celltypeLabel; 758 const char *name[4]; 759 const PetscScalar *a; 760 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 761 762 PetscFunctionBegin; 763 PetscCall(DMGetDimension(dm, &dim)); 764 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 765 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 766 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 767 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 768 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 769 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 770 PetscCall(VecGetArrayRead(coordinates, &a)); 771 name[0] = "vertex"; 772 name[1] = "edge"; 773 name[dim - 1] = "face"; 774 name[dim] = "cell"; 775 for (c = cStart; c < cEnd; ++c) { 776 PetscInt *closure = NULL; 777 PetscInt closureSize, cl, ct; 778 779 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 780 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 781 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 782 PetscCall(PetscViewerASCIIPushTab(viewer)); 783 for (cl = 0; cl < closureSize * 2; cl += 2) { 784 PetscInt point = closure[cl], depth, dof, off, d, p; 785 786 if ((point < pStart) || (point >= pEnd)) continue; 787 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 788 if (!dof) continue; 789 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 790 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 791 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 792 for (p = 0; p < dof / dim; ++p) { 793 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 794 for (d = 0; d < dim; ++d) { 795 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 796 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 797 } 798 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 799 } 800 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 801 } 802 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 803 PetscCall(PetscViewerASCIIPopTab(viewer)); 804 } 805 PetscCall(VecRestoreArrayRead(coordinates, &a)); 806 PetscFunctionReturn(PETSC_SUCCESS); 807 } 808 809 typedef enum { 810 CS_CARTESIAN, 811 CS_POLAR, 812 CS_CYLINDRICAL, 813 CS_SPHERICAL 814 } CoordSystem; 815 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 816 817 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 818 { 819 PetscInt i; 820 821 PetscFunctionBegin; 822 if (dim > 3) { 823 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 824 } else { 825 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 826 827 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 828 switch (cs) { 829 case CS_CARTESIAN: 830 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 831 break; 832 case CS_POLAR: 833 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 834 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 835 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 836 break; 837 case CS_CYLINDRICAL: 838 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 839 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 840 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 841 trcoords[2] = coords[2]; 842 break; 843 case CS_SPHERICAL: 844 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 845 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 846 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 847 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 848 break; 849 } 850 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 851 } 852 PetscFunctionReturn(PETSC_SUCCESS); 853 } 854 855 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 856 { 857 DM_Plex *mesh = (DM_Plex *)dm->data; 858 DM cdm, cdmCell; 859 PetscSection coordSection, coordSectionCell; 860 Vec coordinates, coordinatesCell; 861 PetscViewerFormat format; 862 863 PetscFunctionBegin; 864 PetscCall(PetscViewerGetFormat(viewer, &format)); 865 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 866 const char *name; 867 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 868 PetscInt pStart, pEnd, p, numLabels, l; 869 PetscMPIInt rank, size; 870 871 PetscCall(DMGetCoordinateDM(dm, &cdm)); 872 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 873 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 874 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 875 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 876 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 877 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 878 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 879 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 880 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 881 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 882 PetscCall(DMGetDimension(dm, &dim)); 883 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 884 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 885 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 886 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 887 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 888 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 889 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 890 for (p = pStart; p < pEnd; ++p) { 891 PetscInt dof, off, s; 892 893 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 894 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 895 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 896 } 897 PetscCall(PetscViewerFlush(viewer)); 898 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 899 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 900 for (p = pStart; p < pEnd; ++p) { 901 PetscInt dof, off, c; 902 903 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 904 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 905 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])); 906 } 907 PetscCall(PetscViewerFlush(viewer)); 908 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 909 if (coordSection && coordinates) { 910 CoordSystem cs = CS_CARTESIAN; 911 const PetscScalar *array, *arrayCell = NULL; 912 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 913 PetscMPIInt rank; 914 const char *name; 915 916 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 917 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 918 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 919 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 920 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 921 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 922 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 923 pStart = PetscMin(pvStart, pcStart); 924 pEnd = PetscMax(pvEnd, pcEnd); 925 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 926 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 927 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 928 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 929 930 PetscCall(VecGetArrayRead(coordinates, &array)); 931 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 932 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 933 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 934 for (p = pStart; p < pEnd; ++p) { 935 PetscInt dof, off; 936 937 if (p >= pvStart && p < pvEnd) { 938 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 939 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 940 if (dof) { 941 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 942 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 943 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 944 } 945 } 946 if (cdmCell && p >= pcStart && p < pcEnd) { 947 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 948 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 949 if (dof) { 950 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 951 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 952 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 953 } 954 } 955 } 956 PetscCall(PetscViewerFlush(viewer)); 957 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 958 PetscCall(VecRestoreArrayRead(coordinates, &array)); 959 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 960 } 961 PetscCall(DMGetNumLabels(dm, &numLabels)); 962 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 963 for (l = 0; l < numLabels; ++l) { 964 DMLabel label; 965 PetscBool isdepth; 966 const char *name; 967 968 PetscCall(DMGetLabelName(dm, l, &name)); 969 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 970 if (isdepth) continue; 971 PetscCall(DMGetLabel(dm, name, &label)); 972 PetscCall(DMLabelView(label, viewer)); 973 } 974 if (size > 1) { 975 PetscSF sf; 976 977 PetscCall(DMGetPointSF(dm, &sf)); 978 PetscCall(PetscSFView(sf, viewer)); 979 } 980 if (mesh->periodic.face_sfs) 981 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 982 PetscCall(PetscViewerFlush(viewer)); 983 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 984 const char *name, *color; 985 const char *defcolors[3] = {"gray", "orange", "green"}; 986 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 987 char lname[PETSC_MAX_PATH_LEN]; 988 PetscReal scale = 2.0; 989 PetscReal tikzscale = 1.0; 990 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 991 double tcoords[3]; 992 PetscScalar *coords; 993 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; 994 PetscMPIInt rank, size; 995 char **names, **colors, **lcolors; 996 PetscBool flg, lflg; 997 PetscBT wp = NULL; 998 PetscInt pEnd, pStart; 999 1000 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1001 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1002 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1003 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1004 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1005 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1006 PetscCall(DMGetDimension(dm, &dim)); 1007 PetscCall(DMPlexGetDepth(dm, &depth)); 1008 PetscCall(DMGetNumLabels(dm, &numLabels)); 1009 numLabels = PetscMax(numLabels, 10); 1010 numColors = 10; 1011 numLColors = 10; 1012 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1013 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1014 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1015 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1016 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1017 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1018 n = 4; 1019 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1020 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1021 n = 4; 1022 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1023 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1024 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1025 if (!useLabels) numLabels = 0; 1026 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1027 if (!useColors) { 1028 numColors = 3; 1029 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1030 } 1031 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1032 if (!useColors) { 1033 numLColors = 4; 1034 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1035 } 1036 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1037 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1038 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1039 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1040 if (depth < dim) plotEdges = PETSC_FALSE; 1041 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1042 1043 /* filter points with labelvalue != labeldefaultvalue */ 1044 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1045 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1046 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1047 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1048 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1049 if (lflg) { 1050 DMLabel lbl; 1051 1052 PetscCall(DMGetLabel(dm, lname, &lbl)); 1053 if (lbl) { 1054 PetscInt val, defval; 1055 1056 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1057 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1058 for (c = pStart; c < pEnd; c++) { 1059 PetscInt *closure = NULL; 1060 PetscInt closureSize; 1061 1062 PetscCall(DMLabelGetValue(lbl, c, &val)); 1063 if (val == defval) continue; 1064 1065 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1066 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1067 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1068 } 1069 } 1070 } 1071 1072 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1073 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1074 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1075 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1076 \\documentclass[tikz]{standalone}\n\n\ 1077 \\usepackage{pgflibraryshapes}\n\ 1078 \\usetikzlibrary{backgrounds}\n\ 1079 \\usetikzlibrary{arrows}\n\ 1080 \\begin{document}\n")); 1081 if (size > 1) { 1082 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1083 for (p = 0; p < size; ++p) { 1084 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1085 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1086 } 1087 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1088 } 1089 if (drawHasse) { 1090 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1091 1092 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1093 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1094 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1095 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1096 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1097 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1098 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1099 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1100 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1101 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1102 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1103 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1104 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1105 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1106 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1107 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1108 } 1109 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1110 1111 /* Plot vertices */ 1112 PetscCall(VecGetArray(coordinates, &coords)); 1113 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1114 for (v = vStart; v < vEnd; ++v) { 1115 PetscInt off, dof, d; 1116 PetscBool isLabeled = PETSC_FALSE; 1117 1118 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1119 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1120 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1121 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1122 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1123 for (d = 0; d < dof; ++d) { 1124 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1125 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1126 } 1127 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1128 if (dim == 3) { 1129 PetscReal tmp = tcoords[1]; 1130 tcoords[1] = tcoords[2]; 1131 tcoords[2] = -tmp; 1132 } 1133 for (d = 0; d < dof; ++d) { 1134 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1135 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1136 } 1137 if (drawHasse) color = colors[0 % numColors]; 1138 else color = colors[rank % numColors]; 1139 for (l = 0; l < numLabels; ++l) { 1140 PetscInt val; 1141 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1142 if (val >= 0) { 1143 color = lcolors[l % numLColors]; 1144 isLabeled = PETSC_TRUE; 1145 break; 1146 } 1147 } 1148 if (drawNumbers[0]) { 1149 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1150 } else if (drawColors[0]) { 1151 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1152 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1153 } 1154 PetscCall(VecRestoreArray(coordinates, &coords)); 1155 PetscCall(PetscViewerFlush(viewer)); 1156 /* Plot edges */ 1157 if (plotEdges) { 1158 PetscCall(VecGetArray(coordinates, &coords)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1160 for (e = eStart; e < eEnd; ++e) { 1161 const PetscInt *cone; 1162 PetscInt coneSize, offA, offB, dof, d; 1163 1164 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1165 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1166 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1167 PetscCall(DMPlexGetCone(dm, e, &cone)); 1168 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1169 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1170 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1171 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1172 for (d = 0; d < dof; ++d) { 1173 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1174 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1175 } 1176 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1177 if (dim == 3) { 1178 PetscReal tmp = tcoords[1]; 1179 tcoords[1] = tcoords[2]; 1180 tcoords[2] = -tmp; 1181 } 1182 for (d = 0; d < dof; ++d) { 1183 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1184 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1185 } 1186 if (drawHasse) color = colors[1 % numColors]; 1187 else color = colors[rank % numColors]; 1188 for (l = 0; l < numLabels; ++l) { 1189 PetscInt val; 1190 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1191 if (val >= 0) { 1192 color = lcolors[l % numLColors]; 1193 break; 1194 } 1195 } 1196 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1197 } 1198 PetscCall(VecRestoreArray(coordinates, &coords)); 1199 PetscCall(PetscViewerFlush(viewer)); 1200 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1201 } 1202 /* Plot cells */ 1203 if (dim == 3 || !drawNumbers[1]) { 1204 for (e = eStart; e < eEnd; ++e) { 1205 const PetscInt *cone; 1206 1207 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1208 color = colors[rank % numColors]; 1209 for (l = 0; l < numLabels; ++l) { 1210 PetscInt val; 1211 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1212 if (val >= 0) { 1213 color = lcolors[l % numLColors]; 1214 break; 1215 } 1216 } 1217 PetscCall(DMPlexGetCone(dm, e, &cone)); 1218 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1219 } 1220 } else { 1221 DMPolytopeType ct; 1222 1223 /* Drawing a 2D polygon */ 1224 for (c = cStart; c < cEnd; ++c) { 1225 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1226 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1227 if (DMPolytopeTypeIsHybrid(ct)) { 1228 const PetscInt *cone; 1229 PetscInt coneSize, e; 1230 1231 PetscCall(DMPlexGetCone(dm, c, &cone)); 1232 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1233 for (e = 0; e < coneSize; ++e) { 1234 const PetscInt *econe; 1235 1236 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1237 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)); 1238 } 1239 } else { 1240 PetscInt *closure = NULL; 1241 PetscInt closureSize, Nv = 0, v; 1242 1243 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1244 for (p = 0; p < closureSize * 2; p += 2) { 1245 const PetscInt point = closure[p]; 1246 1247 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1248 } 1249 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1250 for (v = 0; v <= Nv; ++v) { 1251 const PetscInt vertex = closure[v % Nv]; 1252 1253 if (v > 0) { 1254 if (plotEdges) { 1255 const PetscInt *edge; 1256 PetscInt endpoints[2], ne; 1257 1258 endpoints[0] = closure[v - 1]; 1259 endpoints[1] = vertex; 1260 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1261 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1262 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1263 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1264 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1265 } 1266 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1267 } 1268 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1269 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1270 } 1271 } 1272 } 1273 for (c = cStart; c < cEnd; ++c) { 1274 double ccoords[3] = {0.0, 0.0, 0.0}; 1275 PetscBool isLabeled = PETSC_FALSE; 1276 PetscScalar *cellCoords = NULL; 1277 const PetscScalar *array; 1278 PetscInt numCoords, cdim, d; 1279 PetscBool isDG; 1280 1281 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1282 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1283 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1284 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1285 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1286 for (p = 0; p < numCoords / cdim; ++p) { 1287 for (d = 0; d < cdim; ++d) { 1288 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1289 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1290 } 1291 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1292 if (cdim == 3) { 1293 PetscReal tmp = tcoords[1]; 1294 tcoords[1] = tcoords[2]; 1295 tcoords[2] = -tmp; 1296 } 1297 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1298 } 1299 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1300 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1301 for (d = 0; d < cdim; ++d) { 1302 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1303 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1304 } 1305 if (drawHasse) color = colors[depth % numColors]; 1306 else color = colors[rank % numColors]; 1307 for (l = 0; l < numLabels; ++l) { 1308 PetscInt val; 1309 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1310 if (val >= 0) { 1311 color = lcolors[l % numLColors]; 1312 isLabeled = PETSC_TRUE; 1313 break; 1314 } 1315 } 1316 if (drawNumbers[dim]) { 1317 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1318 } else if (drawColors[dim]) { 1319 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1320 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1321 } 1322 if (drawHasse) { 1323 int height = 0; 1324 1325 color = colors[depth % numColors]; 1326 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1327 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1328 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1329 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1330 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1331 1332 if (depth > 2) { 1333 color = colors[1 % numColors]; 1334 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1335 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1336 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1337 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1338 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1339 } 1340 1341 color = colors[1 % numColors]; 1342 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1343 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1344 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1345 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1346 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1347 1348 color = colors[0 % numColors]; 1349 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1350 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1351 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1352 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1353 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1354 1355 for (p = pStart; p < pEnd; ++p) { 1356 const PetscInt *cone; 1357 PetscInt coneSize, cp; 1358 1359 PetscCall(DMPlexGetCone(dm, p, &cone)); 1360 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1361 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1362 } 1363 } 1364 PetscCall(PetscViewerFlush(viewer)); 1365 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1366 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1367 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1368 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1369 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1370 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1371 PetscCall(PetscFree3(names, colors, lcolors)); 1372 PetscCall(PetscBTDestroy(&wp)); 1373 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1374 Vec cown, acown; 1375 VecScatter sct; 1376 ISLocalToGlobalMapping g2l; 1377 IS gid, acis; 1378 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1379 MPI_Group ggroup, ngroup; 1380 PetscScalar *array, nid; 1381 const PetscInt *idxs; 1382 PetscInt *idxs2, *start, *adjacency, *work; 1383 PetscInt64 lm[3], gm[3]; 1384 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1385 PetscMPIInt d1, d2, rank; 1386 1387 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1388 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1389 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1390 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1391 #endif 1392 if (ncomm != MPI_COMM_NULL) { 1393 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1394 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1395 d1 = 0; 1396 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1397 nid = d2; 1398 PetscCallMPI(MPI_Group_free(&ggroup)); 1399 PetscCallMPI(MPI_Group_free(&ngroup)); 1400 PetscCallMPI(MPI_Comm_free(&ncomm)); 1401 } else nid = 0.0; 1402 1403 /* Get connectivity */ 1404 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1405 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1406 1407 /* filter overlapped local cells */ 1408 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1409 PetscCall(ISGetIndices(gid, &idxs)); 1410 PetscCall(ISGetLocalSize(gid, &cum)); 1411 PetscCall(PetscMalloc1(cum, &idxs2)); 1412 for (c = cStart, cum = 0; c < cEnd; c++) { 1413 if (idxs[c - cStart] < 0) continue; 1414 idxs2[cum++] = idxs[c - cStart]; 1415 } 1416 PetscCall(ISRestoreIndices(gid, &idxs)); 1417 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1418 PetscCall(ISDestroy(&gid)); 1419 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1420 1421 /* support for node-aware cell locality */ 1422 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1423 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1424 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1425 PetscCall(VecGetArray(cown, &array)); 1426 for (c = 0; c < numVertices; c++) array[c] = nid; 1427 PetscCall(VecRestoreArray(cown, &array)); 1428 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1429 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1430 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1431 PetscCall(ISDestroy(&acis)); 1432 PetscCall(VecScatterDestroy(&sct)); 1433 PetscCall(VecDestroy(&cown)); 1434 1435 /* compute edgeCut */ 1436 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1437 PetscCall(PetscMalloc1(cum, &work)); 1438 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1439 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1440 PetscCall(ISDestroy(&gid)); 1441 PetscCall(VecGetArray(acown, &array)); 1442 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1443 PetscInt totl; 1444 1445 totl = start[c + 1] - start[c]; 1446 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1447 for (i = 0; i < totl; i++) { 1448 if (work[i] < 0) { 1449 ect += 1; 1450 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1451 } 1452 } 1453 } 1454 PetscCall(PetscFree(work)); 1455 PetscCall(VecRestoreArray(acown, &array)); 1456 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1457 lm[1] = -numVertices; 1458 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1459 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1460 lm[0] = ect; /* edgeCut */ 1461 lm[1] = ectn; /* node-aware edgeCut */ 1462 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1463 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1464 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1465 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1466 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1467 #else 1468 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1469 #endif 1470 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1471 PetscCall(PetscFree(start)); 1472 PetscCall(PetscFree(adjacency)); 1473 PetscCall(VecDestroy(&acown)); 1474 } else { 1475 const char *name; 1476 PetscInt *sizes, *hybsizes, *ghostsizes; 1477 PetscInt locDepth, depth, cellHeight, dim, d; 1478 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1479 PetscInt numLabels, l, maxSize = 17; 1480 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1481 MPI_Comm comm; 1482 PetscMPIInt size, rank; 1483 1484 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1485 PetscCallMPI(MPI_Comm_size(comm, &size)); 1486 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1487 PetscCall(DMGetDimension(dm, &dim)); 1488 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1489 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1490 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1491 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1492 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1493 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1494 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1495 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1496 gcNum = gcEnd - gcStart; 1497 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1498 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1499 for (d = 0; d <= depth; d++) { 1500 PetscInt Nc[2] = {0, 0}, ict; 1501 1502 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1503 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1504 ict = ct0; 1505 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1506 ct0 = (DMPolytopeType)ict; 1507 for (p = pStart; p < pEnd; ++p) { 1508 DMPolytopeType ct; 1509 1510 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1511 if (ct == ct0) ++Nc[0]; 1512 else ++Nc[1]; 1513 } 1514 if (size < maxSize) { 1515 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1516 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1517 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1518 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1519 for (p = 0; p < size; ++p) { 1520 if (rank == 0) { 1521 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1522 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1523 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1524 } 1525 } 1526 } else { 1527 PetscInt locMinMax[2]; 1528 1529 locMinMax[0] = Nc[0] + Nc[1]; 1530 locMinMax[1] = Nc[0] + Nc[1]; 1531 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1532 locMinMax[0] = Nc[1]; 1533 locMinMax[1] = Nc[1]; 1534 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1535 if (d == depth) { 1536 locMinMax[0] = gcNum; 1537 locMinMax[1] = gcNum; 1538 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1539 } 1540 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1541 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1542 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1543 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1544 } 1545 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1546 } 1547 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1548 { 1549 const PetscReal *maxCell; 1550 const PetscReal *L; 1551 PetscBool localized; 1552 1553 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1554 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1555 if (L || localized) { 1556 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1557 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1558 if (L) { 1559 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1560 for (d = 0; d < dim; ++d) { 1561 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1562 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1563 } 1564 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1565 } 1566 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1567 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1568 } 1569 } 1570 PetscCall(DMGetNumLabels(dm, &numLabels)); 1571 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1572 for (l = 0; l < numLabels; ++l) { 1573 DMLabel label; 1574 const char *name; 1575 PetscInt *values; 1576 PetscInt numValues, v; 1577 1578 PetscCall(DMGetLabelName(dm, l, &name)); 1579 PetscCall(DMGetLabel(dm, name, &label)); 1580 PetscCall(DMLabelGetNumValues(label, &numValues)); 1581 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1582 1583 { // Extract array of DMLabel values so it can be sorted 1584 IS is_values; 1585 const PetscInt *is_values_local = NULL; 1586 1587 PetscCall(DMLabelGetValueIS(label, &is_values)); 1588 PetscCall(ISGetIndices(is_values, &is_values_local)); 1589 PetscCall(PetscMalloc1(numValues, &values)); 1590 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1591 PetscCall(PetscSortInt(numValues, values)); 1592 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1593 PetscCall(ISDestroy(&is_values)); 1594 } 1595 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1596 for (v = 0; v < numValues; ++v) { 1597 PetscInt size; 1598 1599 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1600 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1601 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1602 } 1603 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1604 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1605 PetscCall(PetscFree(values)); 1606 } 1607 { 1608 char **labelNames; 1609 PetscInt Nl = numLabels; 1610 PetscBool flg; 1611 1612 PetscCall(PetscMalloc1(Nl, &labelNames)); 1613 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1614 for (l = 0; l < Nl; ++l) { 1615 DMLabel label; 1616 1617 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1618 if (flg) { 1619 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1620 PetscCall(DMLabelView(label, viewer)); 1621 } 1622 PetscCall(PetscFree(labelNames[l])); 1623 } 1624 PetscCall(PetscFree(labelNames)); 1625 } 1626 /* If no fields are specified, people do not want to see adjacency */ 1627 if (dm->Nf) { 1628 PetscInt f; 1629 1630 for (f = 0; f < dm->Nf; ++f) { 1631 const char *name; 1632 1633 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1634 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1635 PetscCall(PetscViewerASCIIPushTab(viewer)); 1636 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1637 if (dm->fields[f].adjacency[0]) { 1638 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1639 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1640 } else { 1641 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1642 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1643 } 1644 PetscCall(PetscViewerASCIIPopTab(viewer)); 1645 } 1646 } 1647 PetscCall(DMGetCoarseDM(dm, &cdm)); 1648 if (cdm) { 1649 PetscCall(PetscViewerASCIIPushTab(viewer)); 1650 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1651 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1652 PetscCall(PetscViewerASCIIPopTab(viewer)); 1653 } 1654 } 1655 PetscFunctionReturn(PETSC_SUCCESS); 1656 } 1657 1658 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1659 { 1660 DMPolytopeType ct; 1661 PetscMPIInt rank; 1662 PetscInt cdim; 1663 1664 PetscFunctionBegin; 1665 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1666 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1667 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1668 switch (ct) { 1669 case DM_POLYTOPE_SEGMENT: 1670 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1671 switch (cdim) { 1672 case 1: { 1673 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1674 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1675 1676 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1677 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1678 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1679 } break; 1680 case 2: { 1681 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1682 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1683 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1684 1685 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1686 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)); 1687 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)); 1688 } break; 1689 default: 1690 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1691 } 1692 break; 1693 case DM_POLYTOPE_TRIANGLE: 1694 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)); 1695 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1696 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1697 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1698 break; 1699 case DM_POLYTOPE_QUADRILATERAL: 1700 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)); 1701 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)); 1702 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1703 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1704 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1705 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1706 break; 1707 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1708 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)); 1709 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)); 1710 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1711 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1712 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1713 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1714 break; 1715 case DM_POLYTOPE_FV_GHOST: 1716 break; 1717 default: 1718 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1719 } 1720 PetscFunctionReturn(PETSC_SUCCESS); 1721 } 1722 1723 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1724 { 1725 PetscReal centroid[2] = {0., 0.}; 1726 PetscMPIInt rank; 1727 PetscMPIInt fillColor; 1728 1729 PetscFunctionBegin; 1730 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1731 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1732 for (PetscInt v = 0; v < Nv; ++v) { 1733 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1734 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1735 } 1736 for (PetscInt e = 0; e < Nv; ++e) { 1737 refCoords[0] = refVertices[e * 2 + 0]; 1738 refCoords[1] = refVertices[e * 2 + 1]; 1739 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1740 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1741 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1742 } 1743 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1744 for (PetscInt d = 0; d < edgeDiv; ++d) { 1745 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)); 1746 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1747 } 1748 } 1749 PetscFunctionReturn(PETSC_SUCCESS); 1750 } 1751 1752 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1753 { 1754 DMPolytopeType ct; 1755 1756 PetscFunctionBegin; 1757 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1758 switch (ct) { 1759 case DM_POLYTOPE_TRIANGLE: { 1760 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1761 1762 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1763 } break; 1764 case DM_POLYTOPE_QUADRILATERAL: { 1765 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1766 1767 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1768 } break; 1769 default: 1770 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1771 } 1772 PetscFunctionReturn(PETSC_SUCCESS); 1773 } 1774 1775 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1776 { 1777 PetscDraw draw; 1778 DM cdm; 1779 PetscSection coordSection; 1780 Vec coordinates; 1781 PetscReal xyl[3], xyr[3]; 1782 PetscReal *refCoords, *edgeCoords; 1783 PetscBool isnull, drawAffine; 1784 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1785 1786 PetscFunctionBegin; 1787 PetscCall(DMGetCoordinateDim(dm, &dim)); 1788 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1789 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1790 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1791 edgeDiv = cDegree + 1; 1792 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1793 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1794 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1795 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1796 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1797 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1798 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1799 1800 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1801 PetscCall(PetscDrawIsNull(draw, &isnull)); 1802 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1803 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1804 1805 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1806 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1807 PetscCall(PetscDrawClear(draw)); 1808 1809 for (c = cStart; c < cEnd; ++c) { 1810 PetscScalar *coords = NULL; 1811 const PetscScalar *coords_arr; 1812 PetscInt numCoords; 1813 PetscBool isDG; 1814 1815 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1816 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1817 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1818 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1819 } 1820 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1821 PetscCall(PetscDrawFlush(draw)); 1822 PetscCall(PetscDrawPause(draw)); 1823 PetscCall(PetscDrawSave(draw)); 1824 PetscFunctionReturn(PETSC_SUCCESS); 1825 } 1826 1827 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1828 { 1829 DM odm = dm, rdm = dm, cdm; 1830 PetscFE fe; 1831 PetscSpace sp; 1832 PetscClassId id; 1833 PetscInt degree; 1834 PetscBool hoView = PETSC_TRUE; 1835 1836 PetscFunctionBegin; 1837 PetscObjectOptionsBegin((PetscObject)dm); 1838 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1839 PetscOptionsEnd(); 1840 PetscCall(PetscObjectReference((PetscObject)dm)); 1841 *hdm = dm; 1842 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1843 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1844 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1845 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1846 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1847 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1848 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1849 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1850 DM cdm, rcdm; 1851 Mat In; 1852 Vec cl, rcl; 1853 1854 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1855 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1856 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1857 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1858 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1859 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1860 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1861 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1862 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1863 PetscCall(MatMult(In, cl, rcl)); 1864 PetscCall(MatDestroy(&In)); 1865 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1866 PetscCall(DMDestroy(&odm)); 1867 odm = rdm; 1868 } 1869 *hdm = rdm; 1870 PetscFunctionReturn(PETSC_SUCCESS); 1871 } 1872 1873 #if defined(PETSC_HAVE_EXODUSII) 1874 #include <exodusII.h> 1875 #include <petscviewerexodusii.h> 1876 #endif 1877 1878 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1879 { 1880 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1881 char name[PETSC_MAX_PATH_LEN]; 1882 1883 PetscFunctionBegin; 1884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1885 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1886 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1887 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1888 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1889 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1890 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1891 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1892 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1893 if (iascii) { 1894 PetscViewerFormat format; 1895 PetscCall(PetscViewerGetFormat(viewer, &format)); 1896 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1897 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1898 } else if (ishdf5) { 1899 #if defined(PETSC_HAVE_HDF5) 1900 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1901 #else 1902 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1903 #endif 1904 } else if (isvtk) { 1905 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1906 } else if (isdraw) { 1907 DM hdm; 1908 1909 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1910 PetscCall(DMPlexView_Draw(hdm, viewer)); 1911 PetscCall(DMDestroy(&hdm)); 1912 } else if (isglvis) { 1913 PetscCall(DMPlexView_GLVis(dm, viewer)); 1914 #if defined(PETSC_HAVE_EXODUSII) 1915 } else if (isexodus) { 1916 /* 1917 exodusII requires that all sets be part of exactly one cell set. 1918 If the dm does not have a "Cell Sets" label defined, we create one 1919 with ID 1, containing all cells. 1920 Note that if the Cell Sets label is defined but does not cover all cells, 1921 we may still have a problem. This should probably be checked here or in the viewer; 1922 */ 1923 PetscInt numCS; 1924 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1925 if (!numCS) { 1926 PetscInt cStart, cEnd, c; 1927 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1928 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1929 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1930 } 1931 PetscCall(DMView_PlexExodusII(dm, viewer)); 1932 #endif 1933 #if defined(PETSC_HAVE_CGNS) 1934 } else if (iscgns) { 1935 PetscCall(DMView_PlexCGNS(dm, viewer)); 1936 #endif 1937 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1938 /* Optionally view the partition */ 1939 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1940 if (flg) { 1941 Vec ranks; 1942 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1943 PetscCall(VecView(ranks, viewer)); 1944 PetscCall(VecDestroy(&ranks)); 1945 } 1946 /* Optionally view a label */ 1947 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1948 if (flg) { 1949 DMLabel label; 1950 Vec val; 1951 1952 PetscCall(DMGetLabel(dm, name, &label)); 1953 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1954 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1955 PetscCall(VecView(val, viewer)); 1956 PetscCall(VecDestroy(&val)); 1957 } 1958 PetscFunctionReturn(PETSC_SUCCESS); 1959 } 1960 1961 /*@ 1962 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1963 1964 Collective 1965 1966 Input Parameters: 1967 + dm - The `DM` whose topology is to be saved 1968 - viewer - The `PetscViewer` to save it in 1969 1970 Level: advanced 1971 1972 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1973 @*/ 1974 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1975 { 1976 PetscBool ishdf5; 1977 1978 PetscFunctionBegin; 1979 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1980 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1981 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1982 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1983 if (ishdf5) { 1984 #if defined(PETSC_HAVE_HDF5) 1985 PetscViewerFormat format; 1986 PetscCall(PetscViewerGetFormat(viewer, &format)); 1987 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1988 IS globalPointNumbering; 1989 1990 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1991 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1992 PetscCall(ISDestroy(&globalPointNumbering)); 1993 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1994 #else 1995 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1996 #endif 1997 } 1998 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1999 PetscFunctionReturn(PETSC_SUCCESS); 2000 } 2001 2002 /*@ 2003 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2004 2005 Collective 2006 2007 Input Parameters: 2008 + dm - The `DM` whose coordinates are to be saved 2009 - viewer - The `PetscViewer` for saving 2010 2011 Level: advanced 2012 2013 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2014 @*/ 2015 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2016 { 2017 PetscBool ishdf5; 2018 2019 PetscFunctionBegin; 2020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2021 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2022 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2023 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2024 if (ishdf5) { 2025 #if defined(PETSC_HAVE_HDF5) 2026 PetscViewerFormat format; 2027 PetscCall(PetscViewerGetFormat(viewer, &format)); 2028 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2029 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2030 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2031 #else 2032 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2033 #endif 2034 } 2035 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2036 PetscFunctionReturn(PETSC_SUCCESS); 2037 } 2038 2039 /*@ 2040 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2041 2042 Collective 2043 2044 Input Parameters: 2045 + dm - The `DM` whose labels are to be saved 2046 - viewer - The `PetscViewer` for saving 2047 2048 Level: advanced 2049 2050 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2051 @*/ 2052 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2053 { 2054 PetscBool ishdf5; 2055 2056 PetscFunctionBegin; 2057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2058 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2060 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2061 if (ishdf5) { 2062 #if defined(PETSC_HAVE_HDF5) 2063 IS globalPointNumbering; 2064 PetscViewerFormat format; 2065 2066 PetscCall(PetscViewerGetFormat(viewer, &format)); 2067 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2068 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2069 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2070 PetscCall(ISDestroy(&globalPointNumbering)); 2071 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2072 #else 2073 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2074 #endif 2075 } 2076 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2077 PetscFunctionReturn(PETSC_SUCCESS); 2078 } 2079 2080 /*@ 2081 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2082 2083 Collective 2084 2085 Input Parameters: 2086 + dm - The `DM` that contains the topology on which the section to be saved is defined 2087 . viewer - The `PetscViewer` for saving 2088 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2089 2090 Level: advanced 2091 2092 Notes: 2093 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. 2094 2095 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. 2096 2097 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2098 @*/ 2099 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2100 { 2101 PetscBool ishdf5; 2102 2103 PetscFunctionBegin; 2104 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2105 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2106 if (!sectiondm) sectiondm = dm; 2107 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2108 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2109 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2110 if (ishdf5) { 2111 #if defined(PETSC_HAVE_HDF5) 2112 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2113 #else 2114 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2115 #endif 2116 } 2117 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2118 PetscFunctionReturn(PETSC_SUCCESS); 2119 } 2120 2121 /*@ 2122 DMPlexGlobalVectorView - Saves a global vector 2123 2124 Collective 2125 2126 Input Parameters: 2127 + dm - The `DM` that represents the topology 2128 . viewer - The `PetscViewer` to save data with 2129 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2130 - vec - The global vector to be saved 2131 2132 Level: advanced 2133 2134 Notes: 2135 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. 2136 2137 Calling sequence: 2138 .vb 2139 DMCreate(PETSC_COMM_WORLD, &dm); 2140 DMSetType(dm, DMPLEX); 2141 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2142 DMClone(dm, §iondm); 2143 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2144 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2145 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2146 PetscSectionSetChart(section, pStart, pEnd); 2147 PetscSectionSetUp(section); 2148 DMSetLocalSection(sectiondm, section); 2149 PetscSectionDestroy(§ion); 2150 DMGetGlobalVector(sectiondm, &vec); 2151 PetscObjectSetName((PetscObject)vec, "vec_name"); 2152 DMPlexTopologyView(dm, viewer); 2153 DMPlexSectionView(dm, viewer, sectiondm); 2154 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2155 DMRestoreGlobalVector(sectiondm, &vec); 2156 DMDestroy(§iondm); 2157 DMDestroy(&dm); 2158 .ve 2159 2160 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2161 @*/ 2162 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2163 { 2164 PetscBool ishdf5; 2165 2166 PetscFunctionBegin; 2167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2168 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2169 if (!sectiondm) sectiondm = dm; 2170 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2171 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2172 /* Check consistency */ 2173 { 2174 PetscSection section; 2175 PetscBool includesConstraints; 2176 PetscInt m, m1; 2177 2178 PetscCall(VecGetLocalSize(vec, &m1)); 2179 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2180 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2181 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2182 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2183 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2184 } 2185 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2186 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2187 if (ishdf5) { 2188 #if defined(PETSC_HAVE_HDF5) 2189 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2190 #else 2191 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2192 #endif 2193 } 2194 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2195 PetscFunctionReturn(PETSC_SUCCESS); 2196 } 2197 2198 /*@ 2199 DMPlexLocalVectorView - Saves a local vector 2200 2201 Collective 2202 2203 Input Parameters: 2204 + dm - The `DM` that represents the topology 2205 . viewer - The `PetscViewer` to save data with 2206 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2207 - vec - The local vector to be saved 2208 2209 Level: advanced 2210 2211 Note: 2212 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. 2213 2214 Calling sequence: 2215 .vb 2216 DMCreate(PETSC_COMM_WORLD, &dm); 2217 DMSetType(dm, DMPLEX); 2218 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2219 DMClone(dm, §iondm); 2220 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2221 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2222 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2223 PetscSectionSetChart(section, pStart, pEnd); 2224 PetscSectionSetUp(section); 2225 DMSetLocalSection(sectiondm, section); 2226 DMGetLocalVector(sectiondm, &vec); 2227 PetscObjectSetName((PetscObject)vec, "vec_name"); 2228 DMPlexTopologyView(dm, viewer); 2229 DMPlexSectionView(dm, viewer, sectiondm); 2230 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2231 DMRestoreLocalVector(sectiondm, &vec); 2232 DMDestroy(§iondm); 2233 DMDestroy(&dm); 2234 .ve 2235 2236 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2237 @*/ 2238 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2239 { 2240 PetscBool ishdf5; 2241 2242 PetscFunctionBegin; 2243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2244 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2245 if (!sectiondm) sectiondm = dm; 2246 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2247 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2248 /* Check consistency */ 2249 { 2250 PetscSection section; 2251 PetscBool includesConstraints; 2252 PetscInt m, m1; 2253 2254 PetscCall(VecGetLocalSize(vec, &m1)); 2255 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2256 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2257 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2258 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2259 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2260 } 2261 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2262 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2263 if (ishdf5) { 2264 #if defined(PETSC_HAVE_HDF5) 2265 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2266 #else 2267 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2268 #endif 2269 } 2270 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2271 PetscFunctionReturn(PETSC_SUCCESS); 2272 } 2273 2274 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2275 { 2276 PetscBool ishdf5; 2277 2278 PetscFunctionBegin; 2279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2280 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2281 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2282 if (ishdf5) { 2283 #if defined(PETSC_HAVE_HDF5) 2284 PetscViewerFormat format; 2285 PetscCall(PetscViewerGetFormat(viewer, &format)); 2286 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2287 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2288 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2289 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2290 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2291 PetscFunctionReturn(PETSC_SUCCESS); 2292 #else 2293 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2294 #endif 2295 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2296 } 2297 2298 /*@ 2299 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2300 2301 Collective 2302 2303 Input Parameters: 2304 + dm - The `DM` into which the topology is loaded 2305 - viewer - The `PetscViewer` for the saved topology 2306 2307 Output Parameter: 2308 . 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; 2309 `NULL` if unneeded 2310 2311 Level: advanced 2312 2313 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2314 `PetscViewer`, `PetscSF` 2315 @*/ 2316 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2317 { 2318 PetscBool ishdf5; 2319 2320 PetscFunctionBegin; 2321 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2322 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2323 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2324 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2325 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2326 if (ishdf5) { 2327 #if defined(PETSC_HAVE_HDF5) 2328 PetscViewerFormat format; 2329 PetscCall(PetscViewerGetFormat(viewer, &format)); 2330 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2331 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2332 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2333 #else 2334 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2335 #endif 2336 } 2337 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2338 PetscFunctionReturn(PETSC_SUCCESS); 2339 } 2340 2341 /*@ 2342 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2343 2344 Collective 2345 2346 Input Parameters: 2347 + dm - The `DM` into which the coordinates are loaded 2348 . viewer - The `PetscViewer` for the saved coordinates 2349 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2350 2351 Level: advanced 2352 2353 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2354 `PetscSF`, `PetscViewer` 2355 @*/ 2356 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2357 { 2358 PetscBool ishdf5; 2359 2360 PetscFunctionBegin; 2361 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2362 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2363 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2364 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2365 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2366 if (ishdf5) { 2367 #if defined(PETSC_HAVE_HDF5) 2368 PetscViewerFormat format; 2369 PetscCall(PetscViewerGetFormat(viewer, &format)); 2370 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2371 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2372 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2373 #else 2374 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2375 #endif 2376 } 2377 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2378 PetscFunctionReturn(PETSC_SUCCESS); 2379 } 2380 2381 /*@ 2382 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2383 2384 Collective 2385 2386 Input Parameters: 2387 + dm - The `DM` into which the labels are loaded 2388 . viewer - The `PetscViewer` for the saved labels 2389 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2390 2391 Level: advanced 2392 2393 Note: 2394 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2395 2396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2397 `PetscSF`, `PetscViewer` 2398 @*/ 2399 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2400 { 2401 PetscBool ishdf5; 2402 2403 PetscFunctionBegin; 2404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2405 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2406 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2407 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2408 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2409 if (ishdf5) { 2410 #if defined(PETSC_HAVE_HDF5) 2411 PetscViewerFormat format; 2412 2413 PetscCall(PetscViewerGetFormat(viewer, &format)); 2414 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2415 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2416 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2417 #else 2418 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2419 #endif 2420 } 2421 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2422 PetscFunctionReturn(PETSC_SUCCESS); 2423 } 2424 2425 /*@ 2426 DMPlexSectionLoad - Loads section into a `DMPLEX` 2427 2428 Collective 2429 2430 Input Parameters: 2431 + dm - The `DM` that represents the topology 2432 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2433 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2434 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2435 2436 Output Parameters: 2437 + 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) 2438 - 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) 2439 2440 Level: advanced 2441 2442 Notes: 2443 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. 2444 2445 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. 2446 2447 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. 2448 2449 Example using 2 processes: 2450 .vb 2451 NX (number of points on dm): 4 2452 sectionA : the on-disk section 2453 vecA : a vector associated with sectionA 2454 sectionB : sectiondm's local section constructed in this function 2455 vecB (local) : a vector associated with sectiondm's local section 2456 vecB (global) : a vector associated with sectiondm's global section 2457 2458 rank 0 rank 1 2459 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2460 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2461 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2462 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2463 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2464 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2465 sectionB->atlasDof : 1 0 1 | 1 3 2466 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2467 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2468 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2469 .ve 2470 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2471 2472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2473 @*/ 2474 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2475 { 2476 PetscBool ishdf5; 2477 2478 PetscFunctionBegin; 2479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2480 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2481 if (!sectiondm) sectiondm = dm; 2482 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2483 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2484 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2485 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2486 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2487 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2488 if (ishdf5) { 2489 #if defined(PETSC_HAVE_HDF5) 2490 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2491 #else 2492 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2493 #endif 2494 } 2495 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2496 PetscFunctionReturn(PETSC_SUCCESS); 2497 } 2498 2499 /*@ 2500 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2501 2502 Collective 2503 2504 Input Parameters: 2505 + dm - The `DM` that represents the topology 2506 . viewer - The `PetscViewer` that represents the on-disk vector data 2507 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2508 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2509 - vec - The global vector to set values of 2510 2511 Level: advanced 2512 2513 Notes: 2514 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. 2515 2516 Calling sequence: 2517 .vb 2518 DMCreate(PETSC_COMM_WORLD, &dm); 2519 DMSetType(dm, DMPLEX); 2520 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2521 DMPlexTopologyLoad(dm, viewer, &sfX); 2522 DMClone(dm, §iondm); 2523 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2524 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2525 DMGetGlobalVector(sectiondm, &vec); 2526 PetscObjectSetName((PetscObject)vec, "vec_name"); 2527 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2528 DMRestoreGlobalVector(sectiondm, &vec); 2529 PetscSFDestroy(&gsf); 2530 PetscSFDestroy(&sfX); 2531 DMDestroy(§iondm); 2532 DMDestroy(&dm); 2533 .ve 2534 2535 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2536 `PetscSF`, `PetscViewer` 2537 @*/ 2538 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2539 { 2540 PetscBool ishdf5; 2541 2542 PetscFunctionBegin; 2543 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2544 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2545 if (!sectiondm) sectiondm = dm; 2546 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2547 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2548 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2549 /* Check consistency */ 2550 { 2551 PetscSection section; 2552 PetscBool includesConstraints; 2553 PetscInt m, m1; 2554 2555 PetscCall(VecGetLocalSize(vec, &m1)); 2556 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2557 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2558 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2559 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2560 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2561 } 2562 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2563 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2564 if (ishdf5) { 2565 #if defined(PETSC_HAVE_HDF5) 2566 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2567 #else 2568 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2569 #endif 2570 } 2571 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2572 PetscFunctionReturn(PETSC_SUCCESS); 2573 } 2574 2575 /*@ 2576 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2577 2578 Collective 2579 2580 Input Parameters: 2581 + dm - The `DM` that represents the topology 2582 . viewer - The `PetscViewer` that represents the on-disk vector data 2583 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2584 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2585 - vec - The local vector to set values of 2586 2587 Level: advanced 2588 2589 Notes: 2590 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. 2591 2592 Calling sequence: 2593 .vb 2594 DMCreate(PETSC_COMM_WORLD, &dm); 2595 DMSetType(dm, DMPLEX); 2596 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2597 DMPlexTopologyLoad(dm, viewer, &sfX); 2598 DMClone(dm, §iondm); 2599 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2600 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2601 DMGetLocalVector(sectiondm, &vec); 2602 PetscObjectSetName((PetscObject)vec, "vec_name"); 2603 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2604 DMRestoreLocalVector(sectiondm, &vec); 2605 PetscSFDestroy(&lsf); 2606 PetscSFDestroy(&sfX); 2607 DMDestroy(§iondm); 2608 DMDestroy(&dm); 2609 .ve 2610 2611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2612 `PetscSF`, `PetscViewer` 2613 @*/ 2614 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2615 { 2616 PetscBool ishdf5; 2617 2618 PetscFunctionBegin; 2619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2620 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2621 if (!sectiondm) sectiondm = dm; 2622 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2623 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2624 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2625 /* Check consistency */ 2626 { 2627 PetscSection section; 2628 PetscBool includesConstraints; 2629 PetscInt m, m1; 2630 2631 PetscCall(VecGetLocalSize(vec, &m1)); 2632 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2633 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2634 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2635 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2636 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2637 } 2638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2639 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2640 if (ishdf5) { 2641 #if defined(PETSC_HAVE_HDF5) 2642 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2643 #else 2644 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2645 #endif 2646 } 2647 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2648 PetscFunctionReturn(PETSC_SUCCESS); 2649 } 2650 2651 PetscErrorCode DMDestroy_Plex(DM dm) 2652 { 2653 DM_Plex *mesh = (DM_Plex *)dm->data; 2654 2655 PetscFunctionBegin; 2656 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2657 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2658 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2659 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2660 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2661 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2662 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2663 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2664 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2665 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2666 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2667 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2668 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2669 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2670 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2671 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2672 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2673 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2674 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2675 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2676 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2677 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2678 PetscCall(PetscFree(mesh->cones)); 2679 PetscCall(PetscFree(mesh->coneOrientations)); 2680 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2681 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2682 PetscCall(PetscFree(mesh->supports)); 2683 PetscCall(PetscFree(mesh->cellTypes)); 2684 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2685 PetscCall(PetscFree(mesh->tetgenOpts)); 2686 PetscCall(PetscFree(mesh->triangleOpts)); 2687 PetscCall(PetscFree(mesh->transformType)); 2688 PetscCall(PetscFree(mesh->distributionName)); 2689 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2690 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2691 PetscCall(ISDestroy(&mesh->subpointIS)); 2692 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2693 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2694 if (mesh->periodic.face_sfs) { 2695 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2696 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2697 } 2698 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2699 if (mesh->periodic.periodic_points) { 2700 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2701 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2702 } 2703 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2704 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2705 PetscCall(ISDestroy(&mesh->anchorIS)); 2706 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2707 PetscCall(PetscFree(mesh->parents)); 2708 PetscCall(PetscFree(mesh->childIDs)); 2709 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2710 PetscCall(PetscFree(mesh->children)); 2711 PetscCall(DMDestroy(&mesh->referenceTree)); 2712 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2713 PetscCall(PetscFree(mesh->neighbors)); 2714 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2715 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2716 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2717 PetscCall(PetscFree(mesh)); 2718 PetscFunctionReturn(PETSC_SUCCESS); 2719 } 2720 2721 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2722 { 2723 PetscSection sectionGlobal, sectionLocal; 2724 PetscInt bs = -1, mbs; 2725 PetscInt localSize, localStart = 0; 2726 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2727 MatType mtype; 2728 ISLocalToGlobalMapping ltog; 2729 2730 PetscFunctionBegin; 2731 PetscCall(MatInitializePackage()); 2732 mtype = dm->mattype; 2733 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2734 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2735 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2736 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2737 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2738 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2739 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2740 PetscCall(MatSetType(*J, mtype)); 2741 PetscCall(MatSetFromOptions(*J)); 2742 PetscCall(MatGetBlockSize(*J, &mbs)); 2743 if (mbs > 1) bs = mbs; 2744 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2745 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2746 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2747 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2748 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2749 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2750 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2751 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2752 if (!isShell) { 2753 // There are three states with pblocks, since block starts can have no dofs: 2754 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2755 // TRUE) Block Start: The first entry in a block has been added 2756 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2757 PetscBT blst; 2758 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2759 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2760 const PetscInt *perm = NULL; 2761 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2762 PetscInt pStart, pEnd, dof, cdof, num_fields; 2763 2764 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2765 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2766 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2767 2768 PetscCall(PetscCalloc1(localSize, &pblocks)); 2769 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2770 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2771 // We need to process in the permuted order to get block sizes right 2772 for (PetscInt point = pStart; point < pEnd; ++point) { 2773 const PetscInt p = perm ? perm[point] : point; 2774 2775 switch (dm->blocking_type) { 2776 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2777 PetscInt bdof, offset; 2778 2779 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2780 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2781 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2782 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2783 if (dof > 0) { 2784 // State change 2785 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2786 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2787 2788 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2789 // Signal block concatenation 2790 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2791 } 2792 dof = dof < 0 ? -(dof + 1) : dof; 2793 bdof = cdof && (dof - cdof) ? 1 : dof; 2794 if (dof) { 2795 if (bs < 0) { 2796 bs = bdof; 2797 } else if (bs != bdof) { 2798 bs = 1; 2799 } 2800 } 2801 } break; 2802 case DM_BLOCKING_FIELD_NODE: { 2803 for (PetscInt field = 0; field < num_fields; field++) { 2804 PetscInt num_comp, bdof, offset; 2805 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2806 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2807 if (dof < 0) continue; 2808 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2809 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2810 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); 2811 PetscInt num_nodes = dof / num_comp; 2812 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2813 // Handle possibly constant block size (unlikely) 2814 bdof = cdof && (dof - cdof) ? 1 : dof; 2815 if (dof) { 2816 if (bs < 0) { 2817 bs = bdof; 2818 } else if (bs != bdof) { 2819 bs = 1; 2820 } 2821 } 2822 } 2823 } break; 2824 } 2825 } 2826 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2827 /* Must have same blocksize on all procs (some might have no points) */ 2828 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2829 bsLocal[1] = bs; 2830 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2831 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2832 else bs = bsMinMax[0]; 2833 bs = PetscMax(1, bs); 2834 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2835 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2836 PetscCall(MatSetBlockSize(*J, bs)); 2837 PetscCall(MatSetUp(*J)); 2838 } else { 2839 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2840 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2841 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2842 } 2843 if (pblocks) { // Consolidate blocks 2844 PetscInt nblocks = 0; 2845 pblocks[0] = PetscAbs(pblocks[0]); 2846 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2847 if (pblocks[i] == 0) continue; 2848 // Negative block size indicates the blocks should be concatenated 2849 if (pblocks[i] < 0) { 2850 pblocks[i] = -pblocks[i]; 2851 pblocks[nblocks - 1] += pblocks[i]; 2852 } else { 2853 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2854 } 2855 for (PetscInt j = 1; j < pblocks[i]; j++) 2856 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); 2857 } 2858 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2859 } 2860 PetscCall(PetscFree(pblocks)); 2861 } 2862 PetscCall(MatSetDM(*J, dm)); 2863 PetscFunctionReturn(PETSC_SUCCESS); 2864 } 2865 2866 /*@ 2867 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2868 2869 Not Collective 2870 2871 Input Parameter: 2872 . dm - The `DMPLEX` 2873 2874 Output Parameter: 2875 . subsection - The subdomain section 2876 2877 Level: developer 2878 2879 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2880 @*/ 2881 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2882 { 2883 DM_Plex *mesh = (DM_Plex *)dm->data; 2884 2885 PetscFunctionBegin; 2886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2887 if (!mesh->subdomainSection) { 2888 PetscSection section; 2889 PetscSF sf; 2890 2891 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2892 PetscCall(DMGetLocalSection(dm, §ion)); 2893 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2894 PetscCall(PetscSFDestroy(&sf)); 2895 } 2896 *subsection = mesh->subdomainSection; 2897 PetscFunctionReturn(PETSC_SUCCESS); 2898 } 2899 2900 /*@ 2901 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2902 2903 Not Collective 2904 2905 Input Parameter: 2906 . dm - The `DMPLEX` 2907 2908 Output Parameters: 2909 + pStart - The first mesh point 2910 - pEnd - The upper bound for mesh points 2911 2912 Level: beginner 2913 2914 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2915 @*/ 2916 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2917 { 2918 DM_Plex *mesh = (DM_Plex *)dm->data; 2919 2920 PetscFunctionBegin; 2921 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2922 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2923 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2924 PetscFunctionReturn(PETSC_SUCCESS); 2925 } 2926 2927 /*@ 2928 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2929 2930 Not Collective 2931 2932 Input Parameters: 2933 + dm - The `DMPLEX` 2934 . pStart - The first mesh point 2935 - pEnd - The upper bound for mesh points 2936 2937 Level: beginner 2938 2939 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2940 @*/ 2941 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2942 { 2943 DM_Plex *mesh = (DM_Plex *)dm->data; 2944 2945 PetscFunctionBegin; 2946 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2947 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2948 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2949 PetscCall(PetscFree(mesh->cellTypes)); 2950 PetscFunctionReturn(PETSC_SUCCESS); 2951 } 2952 2953 /*@ 2954 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2955 2956 Not Collective 2957 2958 Input Parameters: 2959 + dm - The `DMPLEX` 2960 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2961 2962 Output Parameter: 2963 . size - The cone size for point `p` 2964 2965 Level: beginner 2966 2967 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2968 @*/ 2969 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2970 { 2971 DM_Plex *mesh = (DM_Plex *)dm->data; 2972 2973 PetscFunctionBegin; 2974 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2975 PetscAssertPointer(size, 3); 2976 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2977 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2978 PetscFunctionReturn(PETSC_SUCCESS); 2979 } 2980 2981 /*@ 2982 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2983 2984 Not Collective 2985 2986 Input Parameters: 2987 + dm - The `DMPLEX` 2988 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2989 - size - The cone size for point `p` 2990 2991 Level: beginner 2992 2993 Note: 2994 This should be called after `DMPlexSetChart()`. 2995 2996 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2997 @*/ 2998 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2999 { 3000 DM_Plex *mesh = (DM_Plex *)dm->data; 3001 3002 PetscFunctionBegin; 3003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3004 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3005 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3006 PetscFunctionReturn(PETSC_SUCCESS); 3007 } 3008 3009 /*@C 3010 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3011 3012 Not Collective 3013 3014 Input Parameters: 3015 + dm - The `DMPLEX` 3016 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3017 3018 Output Parameter: 3019 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3020 3021 Level: beginner 3022 3023 Fortran Notes: 3024 `cone` must be declared with 3025 .vb 3026 PetscInt, pointer :: cone(:) 3027 .ve 3028 3029 You must also call `DMPlexRestoreCone()` after you finish using the array. 3030 `DMPlexRestoreCone()` is not needed/available in C. 3031 3032 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3033 @*/ 3034 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3035 { 3036 DM_Plex *mesh = (DM_Plex *)dm->data; 3037 PetscInt off; 3038 3039 PetscFunctionBegin; 3040 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3041 PetscAssertPointer(cone, 3); 3042 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3043 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3044 PetscFunctionReturn(PETSC_SUCCESS); 3045 } 3046 3047 /*@ 3048 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3049 3050 Not Collective 3051 3052 Input Parameters: 3053 + dm - The `DMPLEX` 3054 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3055 3056 Output Parameters: 3057 + pConesSection - `PetscSection` describing the layout of `pCones` 3058 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3059 3060 Level: intermediate 3061 3062 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3063 @*/ 3064 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3065 { 3066 PetscSection cs, newcs; 3067 PetscInt *cones; 3068 PetscInt *newarr = NULL; 3069 PetscInt n; 3070 3071 PetscFunctionBegin; 3072 PetscCall(DMPlexGetCones(dm, &cones)); 3073 PetscCall(DMPlexGetConeSection(dm, &cs)); 3074 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3075 if (pConesSection) *pConesSection = newcs; 3076 if (pCones) { 3077 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3078 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3079 } 3080 PetscFunctionReturn(PETSC_SUCCESS); 3081 } 3082 3083 /*@ 3084 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3085 3086 Not Collective 3087 3088 Input Parameters: 3089 + dm - The `DMPLEX` 3090 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3091 3092 Output Parameter: 3093 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3094 3095 Level: advanced 3096 3097 Notes: 3098 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3099 3100 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3101 3102 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3103 `DMPlexGetDepth()`, `IS` 3104 @*/ 3105 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3106 { 3107 IS *expandedPointsAll; 3108 PetscInt depth; 3109 3110 PetscFunctionBegin; 3111 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3112 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3113 PetscAssertPointer(expandedPoints, 3); 3114 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3115 *expandedPoints = expandedPointsAll[0]; 3116 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3117 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3118 PetscFunctionReturn(PETSC_SUCCESS); 3119 } 3120 3121 /*@ 3122 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3123 (DAG points of depth 0, i.e., without cones). 3124 3125 Not Collective 3126 3127 Input Parameters: 3128 + dm - The `DMPLEX` 3129 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3130 3131 Output Parameters: 3132 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3133 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3134 - sections - (optional) An array of sections which describe mappings from points to their cone points 3135 3136 Level: advanced 3137 3138 Notes: 3139 Like `DMPlexGetConeTuple()` but recursive. 3140 3141 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. 3142 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3143 3144 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\: 3145 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3146 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3147 3148 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3149 `DMPlexGetDepth()`, `PetscSection`, `IS` 3150 @*/ 3151 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3152 { 3153 const PetscInt *arr0 = NULL, *cone = NULL; 3154 PetscInt *arr = NULL, *newarr = NULL; 3155 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3156 IS *expandedPoints_; 3157 PetscSection *sections_; 3158 3159 PetscFunctionBegin; 3160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3161 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3162 if (depth) PetscAssertPointer(depth, 3); 3163 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3164 if (sections) PetscAssertPointer(sections, 5); 3165 PetscCall(ISGetLocalSize(points, &n)); 3166 PetscCall(ISGetIndices(points, &arr0)); 3167 PetscCall(DMPlexGetDepth(dm, &depth_)); 3168 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3169 PetscCall(PetscCalloc1(depth_, §ions_)); 3170 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3171 for (d = depth_ - 1; d >= 0; d--) { 3172 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3173 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3174 for (i = 0; i < n; i++) { 3175 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3176 if (arr[i] >= start && arr[i] < end) { 3177 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3178 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3179 } else { 3180 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3181 } 3182 } 3183 PetscCall(PetscSectionSetUp(sections_[d])); 3184 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3185 PetscCall(PetscMalloc1(newn, &newarr)); 3186 for (i = 0; i < n; i++) { 3187 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3188 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3189 if (cn > 1) { 3190 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3191 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3192 } else { 3193 newarr[co] = arr[i]; 3194 } 3195 } 3196 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3197 arr = newarr; 3198 n = newn; 3199 } 3200 PetscCall(ISRestoreIndices(points, &arr0)); 3201 *depth = depth_; 3202 if (expandedPoints) *expandedPoints = expandedPoints_; 3203 else { 3204 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3205 PetscCall(PetscFree(expandedPoints_)); 3206 } 3207 if (sections) *sections = sections_; 3208 else { 3209 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3210 PetscCall(PetscFree(sections_)); 3211 } 3212 PetscFunctionReturn(PETSC_SUCCESS); 3213 } 3214 3215 /*@ 3216 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3217 3218 Not Collective 3219 3220 Input Parameters: 3221 + dm - The `DMPLEX` 3222 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3223 3224 Output Parameters: 3225 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3226 . expandedPoints - (optional) An array of recursively expanded cones 3227 - sections - (optional) An array of sections which describe mappings from points to their cone points 3228 3229 Level: advanced 3230 3231 Note: 3232 See `DMPlexGetConeRecursive()` 3233 3234 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3235 `DMPlexGetDepth()`, `IS`, `PetscSection` 3236 @*/ 3237 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3238 { 3239 PetscInt d, depth_; 3240 3241 PetscFunctionBegin; 3242 PetscCall(DMPlexGetDepth(dm, &depth_)); 3243 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3244 if (depth) *depth = 0; 3245 if (expandedPoints) { 3246 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3247 PetscCall(PetscFree(*expandedPoints)); 3248 } 3249 if (sections) { 3250 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3251 PetscCall(PetscFree(*sections)); 3252 } 3253 PetscFunctionReturn(PETSC_SUCCESS); 3254 } 3255 3256 /*@ 3257 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 3258 3259 Not Collective 3260 3261 Input Parameters: 3262 + dm - The `DMPLEX` 3263 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3264 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3265 3266 Level: beginner 3267 3268 Note: 3269 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3270 3271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3272 @*/ 3273 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3274 { 3275 DM_Plex *mesh = (DM_Plex *)dm->data; 3276 PetscInt dof, off, c; 3277 3278 PetscFunctionBegin; 3279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3280 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3281 if (dof) PetscAssertPointer(cone, 3); 3282 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3283 if (PetscDefined(USE_DEBUG)) { 3284 PetscInt pStart, pEnd; 3285 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3286 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); 3287 for (c = 0; c < dof; ++c) { 3288 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); 3289 mesh->cones[off + c] = cone[c]; 3290 } 3291 } else { 3292 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3293 } 3294 PetscFunctionReturn(PETSC_SUCCESS); 3295 } 3296 3297 /*@C 3298 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3299 3300 Not Collective 3301 3302 Input Parameters: 3303 + dm - The `DMPLEX` 3304 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3305 3306 Output Parameter: 3307 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3308 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3309 3310 Level: beginner 3311 3312 Note: 3313 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3314 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3315 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3316 with the identity. 3317 3318 Fortran Notes: 3319 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3320 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3321 3322 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3323 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3324 @*/ 3325 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3326 { 3327 DM_Plex *mesh = (DM_Plex *)dm->data; 3328 PetscInt off; 3329 3330 PetscFunctionBegin; 3331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3332 if (PetscDefined(USE_DEBUG)) { 3333 PetscInt dof; 3334 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3335 if (dof) PetscAssertPointer(coneOrientation, 3); 3336 } 3337 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3338 3339 *coneOrientation = &mesh->coneOrientations[off]; 3340 PetscFunctionReturn(PETSC_SUCCESS); 3341 } 3342 3343 /*@ 3344 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3345 3346 Not Collective 3347 3348 Input Parameters: 3349 + dm - The `DMPLEX` 3350 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3351 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3352 3353 Level: beginner 3354 3355 Notes: 3356 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3357 3358 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3359 3360 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3361 @*/ 3362 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3363 { 3364 DM_Plex *mesh = (DM_Plex *)dm->data; 3365 PetscInt pStart, pEnd; 3366 PetscInt dof, off, c; 3367 3368 PetscFunctionBegin; 3369 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3370 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3371 if (dof) PetscAssertPointer(coneOrientation, 3); 3372 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3373 if (PetscDefined(USE_DEBUG)) { 3374 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3375 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); 3376 for (c = 0; c < dof; ++c) { 3377 PetscInt cdof, o = coneOrientation[c]; 3378 3379 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3380 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); 3381 mesh->coneOrientations[off + c] = o; 3382 } 3383 } else { 3384 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3385 } 3386 PetscFunctionReturn(PETSC_SUCCESS); 3387 } 3388 3389 /*@ 3390 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3391 3392 Not Collective 3393 3394 Input Parameters: 3395 + dm - The `DMPLEX` 3396 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3397 . conePos - The local index in the cone where the point should be put 3398 - conePoint - The mesh point to insert 3399 3400 Level: beginner 3401 3402 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3403 @*/ 3404 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3405 { 3406 DM_Plex *mesh = (DM_Plex *)dm->data; 3407 PetscInt pStart, pEnd; 3408 PetscInt dof, off; 3409 3410 PetscFunctionBegin; 3411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3412 if (PetscDefined(USE_DEBUG)) { 3413 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3414 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); 3415 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); 3416 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3417 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); 3418 } 3419 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3420 mesh->cones[off + conePos] = conePoint; 3421 PetscFunctionReturn(PETSC_SUCCESS); 3422 } 3423 3424 /*@ 3425 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3426 3427 Not Collective 3428 3429 Input Parameters: 3430 + dm - The `DMPLEX` 3431 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3432 . conePos - The local index in the cone where the point should be put 3433 - coneOrientation - The point orientation to insert 3434 3435 Level: beginner 3436 3437 Note: 3438 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3439 3440 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3441 @*/ 3442 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3443 { 3444 DM_Plex *mesh = (DM_Plex *)dm->data; 3445 PetscInt pStart, pEnd; 3446 PetscInt dof, off; 3447 3448 PetscFunctionBegin; 3449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3450 if (PetscDefined(USE_DEBUG)) { 3451 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3452 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); 3453 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3454 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); 3455 } 3456 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3457 mesh->coneOrientations[off + conePos] = coneOrientation; 3458 PetscFunctionReturn(PETSC_SUCCESS); 3459 } 3460 3461 /*@C 3462 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3463 3464 Not collective 3465 3466 Input Parameters: 3467 + dm - The DMPlex 3468 - p - The point, which must lie in the chart set with DMPlexSetChart() 3469 3470 Output Parameters: 3471 + cone - An array of points which are on the in-edges for point `p` 3472 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3473 integer giving the prescription for cone traversal. 3474 3475 Level: beginner 3476 3477 Notes: 3478 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3479 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3480 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3481 with the identity. 3482 3483 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3484 3485 Fortran Notes: 3486 `cone` and `ornt` must be declared with 3487 .vb 3488 PetscInt, pointer :: cone(:) 3489 PetscInt, pointer :: ornt(:) 3490 .ve 3491 3492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3493 @*/ 3494 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3495 { 3496 DM_Plex *mesh = (DM_Plex *)dm->data; 3497 3498 PetscFunctionBegin; 3499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3500 if (mesh->tr) { 3501 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3502 } else { 3503 PetscInt off; 3504 if (PetscDefined(USE_DEBUG)) { 3505 PetscInt dof; 3506 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3507 if (dof) { 3508 if (cone) PetscAssertPointer(cone, 3); 3509 if (ornt) PetscAssertPointer(ornt, 4); 3510 } 3511 } 3512 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3513 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3514 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3515 } 3516 PetscFunctionReturn(PETSC_SUCCESS); 3517 } 3518 3519 /*@C 3520 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3521 3522 Not Collective 3523 3524 Input Parameters: 3525 + dm - The DMPlex 3526 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3527 . cone - An array of points which are on the in-edges for point p 3528 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3529 integer giving the prescription for cone traversal. 3530 3531 Level: beginner 3532 3533 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3534 @*/ 3535 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3536 { 3537 DM_Plex *mesh = (DM_Plex *)dm->data; 3538 3539 PetscFunctionBegin; 3540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3541 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3542 PetscFunctionReturn(PETSC_SUCCESS); 3543 } 3544 3545 /*@ 3546 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3547 3548 Not Collective 3549 3550 Input Parameters: 3551 + dm - The `DMPLEX` 3552 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3553 3554 Output Parameter: 3555 . size - The support size for point `p` 3556 3557 Level: beginner 3558 3559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3560 @*/ 3561 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3562 { 3563 DM_Plex *mesh = (DM_Plex *)dm->data; 3564 3565 PetscFunctionBegin; 3566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3567 PetscAssertPointer(size, 3); 3568 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3569 PetscFunctionReturn(PETSC_SUCCESS); 3570 } 3571 3572 /*@ 3573 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3574 3575 Not Collective 3576 3577 Input Parameters: 3578 + dm - The `DMPLEX` 3579 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3580 - size - The support size for point `p` 3581 3582 Level: beginner 3583 3584 Note: 3585 This should be called after `DMPlexSetChart()`. 3586 3587 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3588 @*/ 3589 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3590 { 3591 DM_Plex *mesh = (DM_Plex *)dm->data; 3592 3593 PetscFunctionBegin; 3594 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3595 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3596 PetscFunctionReturn(PETSC_SUCCESS); 3597 } 3598 3599 /*@C 3600 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3601 3602 Not Collective 3603 3604 Input Parameters: 3605 + dm - The `DMPLEX` 3606 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3607 3608 Output Parameter: 3609 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3610 3611 Level: beginner 3612 3613 Fortran Notes: 3614 `support` must be declared with 3615 .vb 3616 PetscInt, pointer :: support(:) 3617 .ve 3618 3619 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3620 `DMPlexRestoreSupport()` is not needed/available in C. 3621 3622 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3623 @*/ 3624 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3625 { 3626 DM_Plex *mesh = (DM_Plex *)dm->data; 3627 PetscInt off; 3628 3629 PetscFunctionBegin; 3630 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3631 PetscAssertPointer(support, 3); 3632 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3633 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3634 PetscFunctionReturn(PETSC_SUCCESS); 3635 } 3636 3637 /*@ 3638 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3639 3640 Not Collective 3641 3642 Input Parameters: 3643 + dm - The `DMPLEX` 3644 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3645 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3646 3647 Level: beginner 3648 3649 Note: 3650 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3651 3652 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3653 @*/ 3654 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3655 { 3656 DM_Plex *mesh = (DM_Plex *)dm->data; 3657 PetscInt pStart, pEnd; 3658 PetscInt dof, off, c; 3659 3660 PetscFunctionBegin; 3661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3662 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3663 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3664 if (dof) PetscAssertPointer(support, 3); 3665 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3666 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); 3667 for (c = 0; c < dof; ++c) { 3668 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); 3669 mesh->supports[off + c] = support[c]; 3670 } 3671 PetscFunctionReturn(PETSC_SUCCESS); 3672 } 3673 3674 /*@ 3675 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3676 3677 Not Collective 3678 3679 Input Parameters: 3680 + dm - The `DMPLEX` 3681 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3682 . supportPos - The local index in the cone where the point should be put 3683 - supportPoint - The mesh point to insert 3684 3685 Level: beginner 3686 3687 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3688 @*/ 3689 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3690 { 3691 DM_Plex *mesh = (DM_Plex *)dm->data; 3692 PetscInt pStart, pEnd; 3693 PetscInt dof, off; 3694 3695 PetscFunctionBegin; 3696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3697 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3698 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3699 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3700 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); 3701 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); 3702 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); 3703 mesh->supports[off + supportPos] = supportPoint; 3704 PetscFunctionReturn(PETSC_SUCCESS); 3705 } 3706 3707 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3708 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3709 { 3710 switch (ct) { 3711 case DM_POLYTOPE_SEGMENT: 3712 if (o == -1) return -2; 3713 break; 3714 case DM_POLYTOPE_TRIANGLE: 3715 if (o == -3) return -1; 3716 if (o == -2) return -3; 3717 if (o == -1) return -2; 3718 break; 3719 case DM_POLYTOPE_QUADRILATERAL: 3720 if (o == -4) return -2; 3721 if (o == -3) return -1; 3722 if (o == -2) return -4; 3723 if (o == -1) return -3; 3724 break; 3725 default: 3726 return o; 3727 } 3728 return o; 3729 } 3730 3731 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3732 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3733 { 3734 switch (ct) { 3735 case DM_POLYTOPE_SEGMENT: 3736 if ((o == -2) || (o == 1)) return -1; 3737 if (o == -1) return 0; 3738 break; 3739 case DM_POLYTOPE_TRIANGLE: 3740 if (o == -3) return -2; 3741 if (o == -2) return -1; 3742 if (o == -1) return -3; 3743 break; 3744 case DM_POLYTOPE_QUADRILATERAL: 3745 if (o == -4) return -2; 3746 if (o == -3) return -1; 3747 if (o == -2) return -4; 3748 if (o == -1) return -3; 3749 break; 3750 default: 3751 return o; 3752 } 3753 return o; 3754 } 3755 3756 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3757 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3758 { 3759 PetscInt pStart, pEnd, p; 3760 3761 PetscFunctionBegin; 3762 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3763 for (p = pStart; p < pEnd; ++p) { 3764 const PetscInt *cone, *ornt; 3765 PetscInt coneSize, c; 3766 3767 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3768 PetscCall(DMPlexGetCone(dm, p, &cone)); 3769 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3770 for (c = 0; c < coneSize; ++c) { 3771 DMPolytopeType ct; 3772 const PetscInt o = ornt[c]; 3773 3774 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3775 switch (ct) { 3776 case DM_POLYTOPE_SEGMENT: 3777 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3778 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3779 break; 3780 case DM_POLYTOPE_TRIANGLE: 3781 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3782 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3783 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3784 break; 3785 case DM_POLYTOPE_QUADRILATERAL: 3786 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3787 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3788 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3789 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3790 break; 3791 default: 3792 break; 3793 } 3794 } 3795 } 3796 PetscFunctionReturn(PETSC_SUCCESS); 3797 } 3798 3799 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3800 { 3801 DM_Plex *mesh = (DM_Plex *)dm->data; 3802 3803 PetscFunctionBeginHot; 3804 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3805 if (useCone) { 3806 PetscCall(DMPlexGetConeSize(dm, p, size)); 3807 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3808 } else { 3809 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3810 PetscCall(DMPlexGetSupport(dm, p, arr)); 3811 } 3812 } else { 3813 if (useCone) { 3814 const PetscSection s = mesh->coneSection; 3815 const PetscInt ps = p - s->pStart; 3816 const PetscInt off = s->atlasOff[ps]; 3817 3818 *size = s->atlasDof[ps]; 3819 *arr = mesh->cones + off; 3820 *ornt = mesh->coneOrientations + off; 3821 } else { 3822 const PetscSection s = mesh->supportSection; 3823 const PetscInt ps = p - s->pStart; 3824 const PetscInt off = s->atlasOff[ps]; 3825 3826 *size = s->atlasDof[ps]; 3827 *arr = mesh->supports + off; 3828 } 3829 } 3830 PetscFunctionReturn(PETSC_SUCCESS); 3831 } 3832 3833 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3834 { 3835 DM_Plex *mesh = (DM_Plex *)dm->data; 3836 3837 PetscFunctionBeginHot; 3838 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3839 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3840 } 3841 PetscFunctionReturn(PETSC_SUCCESS); 3842 } 3843 3844 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3845 { 3846 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3847 PetscInt *closure; 3848 const PetscInt *tmp = NULL, *tmpO = NULL; 3849 PetscInt off = 0, tmpSize, t; 3850 3851 PetscFunctionBeginHot; 3852 if (ornt) { 3853 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3854 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; 3855 } 3856 if (*points) { 3857 closure = *points; 3858 } else { 3859 PetscInt maxConeSize, maxSupportSize; 3860 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3861 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3862 } 3863 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3864 if (ct == DM_POLYTOPE_UNKNOWN) { 3865 closure[off++] = p; 3866 closure[off++] = 0; 3867 for (t = 0; t < tmpSize; ++t) { 3868 closure[off++] = tmp[t]; 3869 closure[off++] = tmpO ? tmpO[t] : 0; 3870 } 3871 } else { 3872 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3873 3874 /* We assume that cells with a valid type have faces with a valid type */ 3875 closure[off++] = p; 3876 closure[off++] = ornt; 3877 for (t = 0; t < tmpSize; ++t) { 3878 DMPolytopeType ft; 3879 3880 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3881 closure[off++] = tmp[arr[t]]; 3882 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3883 } 3884 } 3885 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3886 if (numPoints) *numPoints = tmpSize + 1; 3887 if (points) *points = closure; 3888 PetscFunctionReturn(PETSC_SUCCESS); 3889 } 3890 3891 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3892 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3893 { 3894 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3895 const PetscInt *cone, *ornt; 3896 PetscInt *pts, *closure = NULL; 3897 DMPolytopeType ft; 3898 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3899 PetscInt dim, coneSize, c, d, clSize, cl; 3900 3901 PetscFunctionBeginHot; 3902 PetscCall(DMGetDimension(dm, &dim)); 3903 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3904 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3905 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3906 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3907 maxSize = PetscMax(coneSeries, supportSeries); 3908 if (*points) { 3909 pts = *points; 3910 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3911 c = 0; 3912 pts[c++] = point; 3913 pts[c++] = o; 3914 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3915 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), 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(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3921 for (cl = 0; cl < clSize * 2; cl += 2) { 3922 pts[c++] = closure[cl]; 3923 pts[c++] = closure[cl + 1]; 3924 } 3925 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3926 for (d = 2; d < coneSize; ++d) { 3927 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3928 pts[c++] = cone[arr[d * 2 + 0]]; 3929 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3930 } 3931 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3932 if (dim >= 3) { 3933 for (d = 2; d < coneSize; ++d) { 3934 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3935 const PetscInt *fcone, *fornt; 3936 PetscInt fconeSize, fc, i; 3937 3938 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3939 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3940 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3941 for (fc = 0; fc < fconeSize; ++fc) { 3942 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3943 const PetscInt co = farr[fc * 2 + 1]; 3944 3945 for (i = 0; i < c; i += 2) 3946 if (pts[i] == cp) break; 3947 if (i == c) { 3948 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3949 pts[c++] = cp; 3950 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3951 } 3952 } 3953 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3954 } 3955 } 3956 *numPoints = c / 2; 3957 *points = pts; 3958 PetscFunctionReturn(PETSC_SUCCESS); 3959 } 3960 3961 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3962 { 3963 DMPolytopeType ct; 3964 PetscInt *closure, *fifo; 3965 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3966 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3967 PetscInt depth, maxSize; 3968 3969 PetscFunctionBeginHot; 3970 PetscCall(DMPlexGetDepth(dm, &depth)); 3971 if (depth == 1) { 3972 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3973 PetscFunctionReturn(PETSC_SUCCESS); 3974 } 3975 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3976 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; 3977 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3978 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3979 PetscFunctionReturn(PETSC_SUCCESS); 3980 } 3981 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3982 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3983 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3984 maxSize = PetscMax(coneSeries, supportSeries); 3985 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3986 if (*points) { 3987 closure = *points; 3988 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3989 closure[closureSize++] = p; 3990 closure[closureSize++] = ornt; 3991 fifo[fifoSize++] = p; 3992 fifo[fifoSize++] = ornt; 3993 fifo[fifoSize++] = ct; 3994 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3995 while (fifoSize - fifoStart) { 3996 const PetscInt q = fifo[fifoStart++]; 3997 const PetscInt o = fifo[fifoStart++]; 3998 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3999 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4000 const PetscInt *tmp, *tmpO = NULL; 4001 PetscInt tmpSize, t; 4002 4003 if (PetscDefined(USE_DEBUG)) { 4004 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4005 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); 4006 } 4007 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4008 for (t = 0; t < tmpSize; ++t) { 4009 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4010 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4011 const PetscInt cp = tmp[ip]; 4012 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4013 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4014 PetscInt c; 4015 4016 /* Check for duplicate */ 4017 for (c = 0; c < closureSize; c += 2) { 4018 if (closure[c] == cp) break; 4019 } 4020 if (c == closureSize) { 4021 closure[closureSize++] = cp; 4022 closure[closureSize++] = co; 4023 fifo[fifoSize++] = cp; 4024 fifo[fifoSize++] = co; 4025 fifo[fifoSize++] = ct; 4026 } 4027 } 4028 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4029 } 4030 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4031 if (numPoints) *numPoints = closureSize / 2; 4032 if (points) *points = closure; 4033 PetscFunctionReturn(PETSC_SUCCESS); 4034 } 4035 4036 /*@C 4037 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4038 4039 Not Collective 4040 4041 Input Parameters: 4042 + dm - The `DMPLEX` 4043 . p - The mesh point 4044 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4045 4046 Input/Output Parameter: 4047 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4048 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4049 otherwise the provided array is used to hold the values 4050 4051 Output Parameter: 4052 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4053 4054 Level: beginner 4055 4056 Note: 4057 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4058 4059 Fortran Notes: 4060 `points` must be declared with 4061 .vb 4062 PetscInt, pointer :: points(:) 4063 .ve 4064 and is always allocated by the function. 4065 4066 The `numPoints` argument is not present in the Fortran binding. 4067 4068 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4069 @*/ 4070 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4071 { 4072 PetscFunctionBeginHot; 4073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4074 if (numPoints) PetscAssertPointer(numPoints, 4); 4075 if (points) PetscAssertPointer(points, 5); 4076 if (PetscDefined(USE_DEBUG)) { 4077 PetscInt pStart, pEnd; 4078 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4079 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); 4080 } 4081 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4082 PetscFunctionReturn(PETSC_SUCCESS); 4083 } 4084 4085 /*@C 4086 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4087 4088 Not Collective 4089 4090 Input Parameters: 4091 + dm - The `DMPLEX` 4092 . p - The mesh point 4093 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4094 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4095 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4096 4097 Level: beginner 4098 4099 Note: 4100 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4101 4102 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4103 @*/ 4104 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4105 { 4106 PetscFunctionBeginHot; 4107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4108 if (numPoints) *numPoints = 0; 4109 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4110 PetscFunctionReturn(PETSC_SUCCESS); 4111 } 4112 4113 /*@ 4114 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4115 4116 Not Collective 4117 4118 Input Parameter: 4119 . dm - The `DMPLEX` 4120 4121 Output Parameters: 4122 + maxConeSize - The maximum number of in-edges 4123 - maxSupportSize - The maximum number of out-edges 4124 4125 Level: beginner 4126 4127 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4128 @*/ 4129 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4130 { 4131 DM_Plex *mesh = (DM_Plex *)dm->data; 4132 4133 PetscFunctionBegin; 4134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4135 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4136 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4137 PetscFunctionReturn(PETSC_SUCCESS); 4138 } 4139 4140 PetscErrorCode DMSetUp_Plex(DM dm) 4141 { 4142 DM_Plex *mesh = (DM_Plex *)dm->data; 4143 PetscInt size, maxSupportSize; 4144 4145 PetscFunctionBegin; 4146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4147 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4148 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4149 PetscCall(PetscMalloc1(size, &mesh->cones)); 4150 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4151 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4152 if (maxSupportSize) { 4153 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4154 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4155 PetscCall(PetscMalloc1(size, &mesh->supports)); 4156 } 4157 PetscFunctionReturn(PETSC_SUCCESS); 4158 } 4159 4160 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4161 { 4162 PetscFunctionBegin; 4163 if (subdm) PetscCall(DMClone(dm, subdm)); 4164 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4165 if (subdm) (*subdm)->useNatural = dm->useNatural; 4166 if (dm->useNatural && dm->sfMigration) { 4167 PetscSF sfNatural; 4168 4169 (*subdm)->sfMigration = dm->sfMigration; 4170 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4171 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4172 (*subdm)->sfNatural = sfNatural; 4173 } 4174 PetscFunctionReturn(PETSC_SUCCESS); 4175 } 4176 4177 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4178 { 4179 PetscInt i = 0; 4180 4181 PetscFunctionBegin; 4182 PetscCall(DMClone(dms[0], superdm)); 4183 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4184 (*superdm)->useNatural = PETSC_FALSE; 4185 for (i = 0; i < len; i++) { 4186 if (dms[i]->useNatural && dms[i]->sfMigration) { 4187 PetscSF sfNatural; 4188 4189 (*superdm)->sfMigration = dms[i]->sfMigration; 4190 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4191 (*superdm)->useNatural = PETSC_TRUE; 4192 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4193 (*superdm)->sfNatural = sfNatural; 4194 break; 4195 } 4196 } 4197 PetscFunctionReturn(PETSC_SUCCESS); 4198 } 4199 4200 /*@ 4201 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4202 4203 Not Collective 4204 4205 Input Parameter: 4206 . dm - The `DMPLEX` 4207 4208 Level: beginner 4209 4210 Note: 4211 This should be called after all calls to `DMPlexSetCone()` 4212 4213 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4214 @*/ 4215 PetscErrorCode DMPlexSymmetrize(DM dm) 4216 { 4217 DM_Plex *mesh = (DM_Plex *)dm->data; 4218 PetscInt *offsets; 4219 PetscInt supportSize; 4220 PetscInt pStart, pEnd, p; 4221 4222 PetscFunctionBegin; 4223 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4224 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4225 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4226 /* Calculate support sizes */ 4227 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4228 for (p = pStart; p < pEnd; ++p) { 4229 PetscInt dof, off, c; 4230 4231 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4232 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4233 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4234 } 4235 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4236 /* Calculate supports */ 4237 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4238 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4239 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4240 for (p = pStart; p < pEnd; ++p) { 4241 PetscInt dof, off, c; 4242 4243 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4244 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4245 for (c = off; c < off + dof; ++c) { 4246 const PetscInt q = mesh->cones[c]; 4247 PetscInt offS; 4248 4249 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4250 4251 mesh->supports[offS + offsets[q]] = p; 4252 ++offsets[q]; 4253 } 4254 } 4255 PetscCall(PetscFree(offsets)); 4256 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4257 PetscFunctionReturn(PETSC_SUCCESS); 4258 } 4259 4260 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4261 { 4262 IS stratumIS; 4263 4264 PetscFunctionBegin; 4265 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4266 if (PetscDefined(USE_DEBUG)) { 4267 PetscInt qStart, qEnd, numLevels, level; 4268 PetscBool overlap = PETSC_FALSE; 4269 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4270 for (level = 0; level < numLevels; level++) { 4271 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4272 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4273 overlap = PETSC_TRUE; 4274 break; 4275 } 4276 } 4277 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); 4278 } 4279 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4280 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4281 PetscCall(ISDestroy(&stratumIS)); 4282 PetscFunctionReturn(PETSC_SUCCESS); 4283 } 4284 4285 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4286 { 4287 PetscInt *pMin, *pMax; 4288 PetscInt pStart, pEnd; 4289 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4290 4291 PetscFunctionBegin; 4292 { 4293 DMLabel label2; 4294 4295 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4296 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4297 } 4298 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4299 for (PetscInt p = pStart; p < pEnd; ++p) { 4300 DMPolytopeType ct; 4301 4302 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4303 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4304 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4305 } 4306 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4307 for (PetscInt d = dmin; d <= dmax; ++d) { 4308 pMin[d] = PETSC_INT_MAX; 4309 pMax[d] = PETSC_INT_MIN; 4310 } 4311 for (PetscInt p = pStart; p < pEnd; ++p) { 4312 DMPolytopeType ct; 4313 PetscInt d; 4314 4315 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4316 d = DMPolytopeTypeGetDim(ct); 4317 pMin[d] = PetscMin(p, pMin[d]); 4318 pMax[d] = PetscMax(p, pMax[d]); 4319 } 4320 for (PetscInt d = dmin; d <= dmax; ++d) { 4321 if (pMin[d] > pMax[d]) continue; 4322 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4323 } 4324 PetscCall(PetscFree2(pMin, pMax)); 4325 PetscFunctionReturn(PETSC_SUCCESS); 4326 } 4327 4328 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4329 { 4330 PetscInt pStart, pEnd; 4331 PetscInt numRoots = 0, numLeaves = 0; 4332 4333 PetscFunctionBegin; 4334 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4335 { 4336 /* Initialize roots and count leaves */ 4337 PetscInt sMin = PETSC_INT_MAX; 4338 PetscInt sMax = PETSC_INT_MIN; 4339 PetscInt coneSize, supportSize; 4340 4341 for (PetscInt p = pStart; p < pEnd; ++p) { 4342 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4343 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4344 if (!coneSize && supportSize) { 4345 sMin = PetscMin(p, sMin); 4346 sMax = PetscMax(p, sMax); 4347 ++numRoots; 4348 } else if (!supportSize && coneSize) { 4349 ++numLeaves; 4350 } else if (!supportSize && !coneSize) { 4351 /* Isolated points */ 4352 sMin = PetscMin(p, sMin); 4353 sMax = PetscMax(p, sMax); 4354 } 4355 } 4356 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4357 } 4358 4359 if (numRoots + numLeaves == (pEnd - pStart)) { 4360 PetscInt sMin = PETSC_INT_MAX; 4361 PetscInt sMax = PETSC_INT_MIN; 4362 PetscInt coneSize, supportSize; 4363 4364 for (PetscInt p = pStart; p < pEnd; ++p) { 4365 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4366 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4367 if (!supportSize && coneSize) { 4368 sMin = PetscMin(p, sMin); 4369 sMax = PetscMax(p, sMax); 4370 } 4371 } 4372 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4373 } else { 4374 PetscInt level = 0; 4375 PetscInt qStart, qEnd; 4376 4377 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4378 while (qEnd > qStart) { 4379 PetscInt sMin = PETSC_INT_MAX; 4380 PetscInt sMax = PETSC_INT_MIN; 4381 4382 for (PetscInt q = qStart; q < qEnd; ++q) { 4383 const PetscInt *support; 4384 PetscInt supportSize; 4385 4386 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4387 PetscCall(DMPlexGetSupport(dm, q, &support)); 4388 for (PetscInt s = 0; s < supportSize; ++s) { 4389 sMin = PetscMin(support[s], sMin); 4390 sMax = PetscMax(support[s], sMax); 4391 } 4392 } 4393 PetscCall(DMLabelGetNumValues(label, &level)); 4394 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4395 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4396 } 4397 } 4398 PetscFunctionReturn(PETSC_SUCCESS); 4399 } 4400 4401 /*@ 4402 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4403 4404 Collective 4405 4406 Input Parameter: 4407 . dm - The `DMPLEX` 4408 4409 Level: beginner 4410 4411 Notes: 4412 The strata group all points of the same grade, and this function calculates the strata. This 4413 grade can be seen as the height (or depth) of the point in the DAG. 4414 4415 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4416 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4417 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4418 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4419 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4420 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4421 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4422 4423 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4424 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4425 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 4426 to interpolate only that one (e0), so that 4427 .vb 4428 cone(c0) = {e0, v2} 4429 cone(e0) = {v0, v1} 4430 .ve 4431 If `DMPlexStratify()` is run on this mesh, it will give depths 4432 .vb 4433 depth 0 = {v0, v1, v2} 4434 depth 1 = {e0, c0} 4435 .ve 4436 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4437 4438 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4439 4440 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4441 @*/ 4442 PetscErrorCode DMPlexStratify(DM dm) 4443 { 4444 DM_Plex *mesh = (DM_Plex *)dm->data; 4445 DMLabel label; 4446 PetscBool flg = PETSC_FALSE; 4447 4448 PetscFunctionBegin; 4449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4450 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4451 4452 // Create depth label 4453 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4454 PetscCall(DMCreateLabel(dm, "depth")); 4455 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4456 4457 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4458 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4459 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4460 4461 { /* just in case there is an empty process */ 4462 PetscInt numValues, maxValues = 0, v; 4463 4464 PetscCall(DMLabelGetNumValues(label, &numValues)); 4465 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4466 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4467 } 4468 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4469 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4470 PetscFunctionReturn(PETSC_SUCCESS); 4471 } 4472 4473 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4474 { 4475 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4476 PetscInt dim, depth, pheight, coneSize; 4477 4478 PetscFunctionBeginHot; 4479 PetscCall(DMGetDimension(dm, &dim)); 4480 PetscCall(DMPlexGetDepth(dm, &depth)); 4481 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4482 pheight = depth - pdepth; 4483 if (depth <= 1) { 4484 switch (pdepth) { 4485 case 0: 4486 ct = DM_POLYTOPE_POINT; 4487 break; 4488 case 1: 4489 switch (coneSize) { 4490 case 2: 4491 ct = DM_POLYTOPE_SEGMENT; 4492 break; 4493 case 3: 4494 ct = DM_POLYTOPE_TRIANGLE; 4495 break; 4496 case 4: 4497 switch (dim) { 4498 case 2: 4499 ct = DM_POLYTOPE_QUADRILATERAL; 4500 break; 4501 case 3: 4502 ct = DM_POLYTOPE_TETRAHEDRON; 4503 break; 4504 default: 4505 break; 4506 } 4507 break; 4508 case 5: 4509 ct = DM_POLYTOPE_PYRAMID; 4510 break; 4511 case 6: 4512 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4513 break; 4514 case 8: 4515 ct = DM_POLYTOPE_HEXAHEDRON; 4516 break; 4517 default: 4518 break; 4519 } 4520 } 4521 } else { 4522 if (pdepth == 0) { 4523 ct = DM_POLYTOPE_POINT; 4524 } else if (pheight == 0) { 4525 switch (dim) { 4526 case 1: 4527 switch (coneSize) { 4528 case 2: 4529 ct = DM_POLYTOPE_SEGMENT; 4530 break; 4531 default: 4532 break; 4533 } 4534 break; 4535 case 2: 4536 switch (coneSize) { 4537 case 3: 4538 ct = DM_POLYTOPE_TRIANGLE; 4539 break; 4540 case 4: 4541 ct = DM_POLYTOPE_QUADRILATERAL; 4542 break; 4543 default: 4544 break; 4545 } 4546 break; 4547 case 3: 4548 switch (coneSize) { 4549 case 4: 4550 ct = DM_POLYTOPE_TETRAHEDRON; 4551 break; 4552 case 5: { 4553 const PetscInt *cone; 4554 PetscInt faceConeSize; 4555 4556 PetscCall(DMPlexGetCone(dm, p, &cone)); 4557 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4558 switch (faceConeSize) { 4559 case 3: 4560 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4561 break; 4562 case 4: 4563 ct = DM_POLYTOPE_PYRAMID; 4564 break; 4565 } 4566 } break; 4567 case 6: 4568 ct = DM_POLYTOPE_HEXAHEDRON; 4569 break; 4570 default: 4571 break; 4572 } 4573 break; 4574 default: 4575 break; 4576 } 4577 } else if (pheight > 0) { 4578 switch (coneSize) { 4579 case 2: 4580 ct = DM_POLYTOPE_SEGMENT; 4581 break; 4582 case 3: 4583 ct = DM_POLYTOPE_TRIANGLE; 4584 break; 4585 case 4: 4586 ct = DM_POLYTOPE_QUADRILATERAL; 4587 break; 4588 default: 4589 break; 4590 } 4591 } 4592 } 4593 *pt = ct; 4594 PetscFunctionReturn(PETSC_SUCCESS); 4595 } 4596 4597 /*@ 4598 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4599 4600 Collective 4601 4602 Input Parameter: 4603 . dm - The `DMPLEX` 4604 4605 Level: developer 4606 4607 Note: 4608 This function is normally called automatically when a cell type is requested. It creates an 4609 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4610 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4611 4612 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4613 4614 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4615 @*/ 4616 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4617 { 4618 DM_Plex *mesh; 4619 DMLabel ctLabel; 4620 PetscInt pStart, pEnd, p; 4621 4622 PetscFunctionBegin; 4623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4624 mesh = (DM_Plex *)dm->data; 4625 PetscCall(DMCreateLabel(dm, "celltype")); 4626 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4627 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4628 PetscCall(PetscFree(mesh->cellTypes)); 4629 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4630 for (p = pStart; p < pEnd; ++p) { 4631 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4632 PetscInt pdepth; 4633 4634 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4635 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4636 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]); 4637 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4638 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4639 } 4640 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4641 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4642 PetscFunctionReturn(PETSC_SUCCESS); 4643 } 4644 4645 /*@C 4646 DMPlexGetJoin - Get an array for the join of the set of points 4647 4648 Not Collective 4649 4650 Input Parameters: 4651 + dm - The `DMPLEX` object 4652 . numPoints - The number of input points for the join 4653 - points - The input points 4654 4655 Output Parameters: 4656 + numCoveredPoints - The number of points in the join 4657 - coveredPoints - The points in the join 4658 4659 Level: intermediate 4660 4661 Note: 4662 Currently, this is restricted to a single level join 4663 4664 Fortran Notes: 4665 `converedPoints` must be declared with 4666 .vb 4667 PetscInt, pointer :: coveredPints(:) 4668 .ve 4669 4670 The `numCoveredPoints` argument is not present in the Fortran binding. 4671 4672 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4673 @*/ 4674 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4675 { 4676 DM_Plex *mesh = (DM_Plex *)dm->data; 4677 PetscInt *join[2]; 4678 PetscInt joinSize, i = 0; 4679 PetscInt dof, off, p, c, m; 4680 PetscInt maxSupportSize; 4681 4682 PetscFunctionBegin; 4683 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4684 PetscAssertPointer(points, 3); 4685 PetscAssertPointer(numCoveredPoints, 4); 4686 PetscAssertPointer(coveredPoints, 5); 4687 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4688 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4689 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4690 /* Copy in support of first point */ 4691 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4692 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4693 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4694 /* Check each successive support */ 4695 for (p = 1; p < numPoints; ++p) { 4696 PetscInt newJoinSize = 0; 4697 4698 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4699 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4700 for (c = 0; c < dof; ++c) { 4701 const PetscInt point = mesh->supports[off + c]; 4702 4703 for (m = 0; m < joinSize; ++m) { 4704 if (point == join[i][m]) { 4705 join[1 - i][newJoinSize++] = point; 4706 break; 4707 } 4708 } 4709 } 4710 joinSize = newJoinSize; 4711 i = 1 - i; 4712 } 4713 *numCoveredPoints = joinSize; 4714 *coveredPoints = join[i]; 4715 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4716 PetscFunctionReturn(PETSC_SUCCESS); 4717 } 4718 4719 /*@C 4720 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4721 4722 Not Collective 4723 4724 Input Parameters: 4725 + dm - The `DMPLEX` object 4726 . numPoints - The number of input points for the join 4727 - points - The input points 4728 4729 Output Parameters: 4730 + numCoveredPoints - The number of points in the join 4731 - coveredPoints - The points in the join 4732 4733 Level: intermediate 4734 4735 Fortran Notes: 4736 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4737 4738 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4739 @*/ 4740 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4741 { 4742 PetscFunctionBegin; 4743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4744 if (points) PetscAssertPointer(points, 3); 4745 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4746 PetscAssertPointer(coveredPoints, 5); 4747 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4748 if (numCoveredPoints) *numCoveredPoints = 0; 4749 PetscFunctionReturn(PETSC_SUCCESS); 4750 } 4751 4752 /*@C 4753 DMPlexGetFullJoin - Get an array for the join of the set of points 4754 4755 Not Collective 4756 4757 Input Parameters: 4758 + dm - The `DMPLEX` object 4759 . numPoints - The number of input points for the join 4760 - points - The input points, its length is `numPoints` 4761 4762 Output Parameters: 4763 + numCoveredPoints - The number of points in the join 4764 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4765 4766 Level: intermediate 4767 4768 Fortran Notes: 4769 `points` and `converedPoints` must be declared with 4770 .vb 4771 PetscInt, pointer :: points(:) 4772 PetscInt, pointer :: coveredPints(:) 4773 .ve 4774 4775 The `numCoveredPoints` argument is not present in the Fortran binding. 4776 4777 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4778 @*/ 4779 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4780 { 4781 PetscInt *offsets, **closures; 4782 PetscInt *join[2]; 4783 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4784 PetscInt p, d, c, m, ms; 4785 4786 PetscFunctionBegin; 4787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4788 PetscAssertPointer(points, 3); 4789 PetscAssertPointer(numCoveredPoints, 4); 4790 PetscAssertPointer(coveredPoints, 5); 4791 4792 PetscCall(DMPlexGetDepth(dm, &depth)); 4793 PetscCall(PetscCalloc1(numPoints, &closures)); 4794 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4795 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4796 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4797 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4798 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4799 4800 for (p = 0; p < numPoints; ++p) { 4801 PetscInt closureSize; 4802 4803 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4804 4805 offsets[p * (depth + 2) + 0] = 0; 4806 for (d = 0; d < depth + 1; ++d) { 4807 PetscInt pStart, pEnd, i; 4808 4809 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4810 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4811 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4812 offsets[p * (depth + 2) + d + 1] = i; 4813 break; 4814 } 4815 } 4816 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4817 } 4818 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); 4819 } 4820 for (d = 0; d < depth + 1; ++d) { 4821 PetscInt dof; 4822 4823 /* Copy in support of first point */ 4824 dof = offsets[d + 1] - offsets[d]; 4825 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4826 /* Check each successive cone */ 4827 for (p = 1; p < numPoints && joinSize; ++p) { 4828 PetscInt newJoinSize = 0; 4829 4830 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4831 for (c = 0; c < dof; ++c) { 4832 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4833 4834 for (m = 0; m < joinSize; ++m) { 4835 if (point == join[i][m]) { 4836 join[1 - i][newJoinSize++] = point; 4837 break; 4838 } 4839 } 4840 } 4841 joinSize = newJoinSize; 4842 i = 1 - i; 4843 } 4844 if (joinSize) break; 4845 } 4846 *numCoveredPoints = joinSize; 4847 *coveredPoints = join[i]; 4848 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4849 PetscCall(PetscFree(closures)); 4850 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4851 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4852 PetscFunctionReturn(PETSC_SUCCESS); 4853 } 4854 4855 /*@C 4856 DMPlexGetMeet - Get an array for the meet of the set of points 4857 4858 Not Collective 4859 4860 Input Parameters: 4861 + dm - The `DMPLEX` object 4862 . numPoints - The number of input points for the meet 4863 - points - The input points, of length `numPoints` 4864 4865 Output Parameters: 4866 + numCoveringPoints - The number of points in the meet 4867 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4868 4869 Level: intermediate 4870 4871 Note: 4872 Currently, this is restricted to a single level meet 4873 4874 Fortran Notes: 4875 `coveringPoints` must be declared with 4876 .vb 4877 PetscInt, pointer :: coveringPoints(:) 4878 .ve 4879 4880 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4881 4882 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4883 @*/ 4884 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4885 { 4886 DM_Plex *mesh = (DM_Plex *)dm->data; 4887 PetscInt *meet[2]; 4888 PetscInt meetSize, i = 0; 4889 PetscInt dof, off, p, c, m; 4890 PetscInt maxConeSize; 4891 4892 PetscFunctionBegin; 4893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4894 PetscAssertPointer(points, 3); 4895 PetscAssertPointer(numCoveringPoints, 4); 4896 PetscAssertPointer(coveringPoints, 5); 4897 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4898 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4899 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4900 /* Copy in cone of first point */ 4901 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4902 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4903 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4904 /* Check each successive cone */ 4905 for (p = 1; p < numPoints; ++p) { 4906 PetscInt newMeetSize = 0; 4907 4908 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4909 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4910 for (c = 0; c < dof; ++c) { 4911 const PetscInt point = mesh->cones[off + c]; 4912 4913 for (m = 0; m < meetSize; ++m) { 4914 if (point == meet[i][m]) { 4915 meet[1 - i][newMeetSize++] = point; 4916 break; 4917 } 4918 } 4919 } 4920 meetSize = newMeetSize; 4921 i = 1 - i; 4922 } 4923 *numCoveringPoints = meetSize; 4924 *coveringPoints = meet[i]; 4925 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4926 PetscFunctionReturn(PETSC_SUCCESS); 4927 } 4928 4929 /*@C 4930 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 4931 4932 Not Collective 4933 4934 Input Parameters: 4935 + dm - The `DMPLEX` object 4936 . numPoints - The number of input points for the meet 4937 - points - The input points 4938 4939 Output Parameters: 4940 + numCoveredPoints - The number of points in the meet 4941 - coveredPoints - The points in the meet 4942 4943 Level: intermediate 4944 4945 Fortran Notes: 4946 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4947 4948 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4949 @*/ 4950 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4951 { 4952 PetscFunctionBegin; 4953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4954 if (points) PetscAssertPointer(points, 3); 4955 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4956 PetscAssertPointer(coveredPoints, 5); 4957 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4958 if (numCoveredPoints) *numCoveredPoints = 0; 4959 PetscFunctionReturn(PETSC_SUCCESS); 4960 } 4961 4962 /*@C 4963 DMPlexGetFullMeet - Get an array for the meet of the set of points 4964 4965 Not Collective 4966 4967 Input Parameters: 4968 + dm - The `DMPLEX` object 4969 . numPoints - The number of input points for the meet 4970 - points - The input points, of length `numPoints` 4971 4972 Output Parameters: 4973 + numCoveredPoints - The number of points in the meet 4974 - coveredPoints - The points in the meet, of length `numCoveredPoints` 4975 4976 Level: intermediate 4977 4978 Fortran Notes: 4979 `points` and `coveredPoints` must be declared with 4980 .vb 4981 PetscInt, pointer :: points(:) 4982 PetscInt, pointer :: coveredPoints(:) 4983 .ve 4984 4985 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4986 4987 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4988 @*/ 4989 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4990 { 4991 PetscInt *offsets, **closures; 4992 PetscInt *meet[2]; 4993 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4994 PetscInt p, h, c, m, mc; 4995 4996 PetscFunctionBegin; 4997 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4998 PetscAssertPointer(points, 3); 4999 PetscAssertPointer(numCoveredPoints, 4); 5000 PetscAssertPointer(coveredPoints, 5); 5001 5002 PetscCall(DMPlexGetDepth(dm, &height)); 5003 PetscCall(PetscMalloc1(numPoints, &closures)); 5004 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5005 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5006 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5007 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5008 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5009 5010 for (p = 0; p < numPoints; ++p) { 5011 PetscInt closureSize; 5012 5013 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5014 5015 offsets[p * (height + 2) + 0] = 0; 5016 for (h = 0; h < height + 1; ++h) { 5017 PetscInt pStart, pEnd, i; 5018 5019 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5020 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5021 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5022 offsets[p * (height + 2) + h + 1] = i; 5023 break; 5024 } 5025 } 5026 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5027 } 5028 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); 5029 } 5030 for (h = 0; h < height + 1; ++h) { 5031 PetscInt dof; 5032 5033 /* Copy in cone of first point */ 5034 dof = offsets[h + 1] - offsets[h]; 5035 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5036 /* Check each successive cone */ 5037 for (p = 1; p < numPoints && meetSize; ++p) { 5038 PetscInt newMeetSize = 0; 5039 5040 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5041 for (c = 0; c < dof; ++c) { 5042 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5043 5044 for (m = 0; m < meetSize; ++m) { 5045 if (point == meet[i][m]) { 5046 meet[1 - i][newMeetSize++] = point; 5047 break; 5048 } 5049 } 5050 } 5051 meetSize = newMeetSize; 5052 i = 1 - i; 5053 } 5054 if (meetSize) break; 5055 } 5056 *numCoveredPoints = meetSize; 5057 *coveredPoints = meet[i]; 5058 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5059 PetscCall(PetscFree(closures)); 5060 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5061 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5062 PetscFunctionReturn(PETSC_SUCCESS); 5063 } 5064 5065 /*@ 5066 DMPlexEqual - Determine if two `DM` have the same topology 5067 5068 Not Collective 5069 5070 Input Parameters: 5071 + dmA - A `DMPLEX` object 5072 - dmB - A `DMPLEX` object 5073 5074 Output Parameter: 5075 . equal - `PETSC_TRUE` if the topologies are identical 5076 5077 Level: intermediate 5078 5079 Note: 5080 We are not solving graph isomorphism, so we do not permute. 5081 5082 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5083 @*/ 5084 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5085 { 5086 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5087 5088 PetscFunctionBegin; 5089 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5090 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5091 PetscAssertPointer(equal, 3); 5092 5093 *equal = PETSC_FALSE; 5094 PetscCall(DMPlexGetDepth(dmA, &depth)); 5095 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5096 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5097 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5098 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5099 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5100 for (p = pStart; p < pEnd; ++p) { 5101 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5102 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5103 5104 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5105 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5106 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5107 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5108 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5109 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5110 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5111 for (c = 0; c < coneSize; ++c) { 5112 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5113 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5114 } 5115 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5116 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5117 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5118 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5119 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5120 for (s = 0; s < supportSize; ++s) { 5121 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5122 } 5123 } 5124 *equal = PETSC_TRUE; 5125 PetscFunctionReturn(PETSC_SUCCESS); 5126 } 5127 5128 /*@ 5129 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5130 5131 Not Collective 5132 5133 Input Parameters: 5134 + dm - The `DMPLEX` 5135 . cellDim - The cell dimension 5136 - numCorners - The number of vertices on a cell 5137 5138 Output Parameter: 5139 . numFaceVertices - The number of vertices on a face 5140 5141 Level: developer 5142 5143 Note: 5144 Of course this can only work for a restricted set of symmetric shapes 5145 5146 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5147 @*/ 5148 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5149 { 5150 MPI_Comm comm; 5151 5152 PetscFunctionBegin; 5153 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5154 PetscAssertPointer(numFaceVertices, 4); 5155 switch (cellDim) { 5156 case 0: 5157 *numFaceVertices = 0; 5158 break; 5159 case 1: 5160 *numFaceVertices = 1; 5161 break; 5162 case 2: 5163 switch (numCorners) { 5164 case 3: /* triangle */ 5165 *numFaceVertices = 2; /* Edge has 2 vertices */ 5166 break; 5167 case 4: /* quadrilateral */ 5168 *numFaceVertices = 2; /* Edge has 2 vertices */ 5169 break; 5170 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5171 *numFaceVertices = 3; /* Edge has 3 vertices */ 5172 break; 5173 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5174 *numFaceVertices = 3; /* Edge has 3 vertices */ 5175 break; 5176 default: 5177 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5178 } 5179 break; 5180 case 3: 5181 switch (numCorners) { 5182 case 4: /* tetradehdron */ 5183 *numFaceVertices = 3; /* Face has 3 vertices */ 5184 break; 5185 case 6: /* tet cohesive cells */ 5186 *numFaceVertices = 4; /* Face has 4 vertices */ 5187 break; 5188 case 8: /* hexahedron */ 5189 *numFaceVertices = 4; /* Face has 4 vertices */ 5190 break; 5191 case 9: /* tet cohesive Lagrange cells */ 5192 *numFaceVertices = 6; /* Face has 6 vertices */ 5193 break; 5194 case 10: /* quadratic tetrahedron */ 5195 *numFaceVertices = 6; /* Face has 6 vertices */ 5196 break; 5197 case 12: /* hex cohesive Lagrange cells */ 5198 *numFaceVertices = 6; /* Face has 6 vertices */ 5199 break; 5200 case 18: /* quadratic tet cohesive Lagrange cells */ 5201 *numFaceVertices = 6; /* Face has 6 vertices */ 5202 break; 5203 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5204 *numFaceVertices = 9; /* Face has 9 vertices */ 5205 break; 5206 default: 5207 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5208 } 5209 break; 5210 default: 5211 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5212 } 5213 PetscFunctionReturn(PETSC_SUCCESS); 5214 } 5215 5216 /*@ 5217 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5218 5219 Not Collective 5220 5221 Input Parameter: 5222 . dm - The `DMPLEX` object 5223 5224 Output Parameter: 5225 . depthLabel - The `DMLabel` recording point depth 5226 5227 Level: developer 5228 5229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5230 @*/ 5231 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5232 { 5233 PetscFunctionBegin; 5234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5235 PetscAssertPointer(depthLabel, 2); 5236 *depthLabel = dm->depthLabel; 5237 PetscFunctionReturn(PETSC_SUCCESS); 5238 } 5239 5240 /*@ 5241 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5242 5243 Not Collective 5244 5245 Input Parameter: 5246 . dm - The `DMPLEX` object 5247 5248 Output Parameter: 5249 . depth - The number of strata (breadth first levels) in the DAG 5250 5251 Level: developer 5252 5253 Notes: 5254 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5255 5256 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5257 5258 An empty mesh gives -1. 5259 5260 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5261 @*/ 5262 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5263 { 5264 DM_Plex *mesh = (DM_Plex *)dm->data; 5265 DMLabel label; 5266 PetscInt d = -1; 5267 5268 PetscFunctionBegin; 5269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5270 PetscAssertPointer(depth, 2); 5271 if (mesh->tr) { 5272 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5273 } else { 5274 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5275 // Allow missing depths 5276 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5277 *depth = d; 5278 } 5279 PetscFunctionReturn(PETSC_SUCCESS); 5280 } 5281 5282 /*@ 5283 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5284 5285 Not Collective 5286 5287 Input Parameters: 5288 + dm - The `DMPLEX` object 5289 - depth - The requested depth 5290 5291 Output Parameters: 5292 + start - The first point at this `depth` 5293 - end - One beyond the last point at this `depth` 5294 5295 Level: developer 5296 5297 Notes: 5298 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5299 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5300 higher dimension, e.g., "edges". 5301 5302 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5303 @*/ 5304 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5305 { 5306 DM_Plex *mesh = (DM_Plex *)dm->data; 5307 DMLabel label; 5308 PetscInt pStart, pEnd; 5309 5310 PetscFunctionBegin; 5311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5312 if (start) { 5313 PetscAssertPointer(start, 3); 5314 *start = 0; 5315 } 5316 if (end) { 5317 PetscAssertPointer(end, 4); 5318 *end = 0; 5319 } 5320 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5321 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5322 if (depth < 0) { 5323 if (start) *start = pStart; 5324 if (end) *end = pEnd; 5325 PetscFunctionReturn(PETSC_SUCCESS); 5326 } 5327 if (mesh->tr) { 5328 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5329 } else { 5330 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5331 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5332 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5333 } 5334 PetscFunctionReturn(PETSC_SUCCESS); 5335 } 5336 5337 /*@ 5338 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5339 5340 Not Collective 5341 5342 Input Parameters: 5343 + dm - The `DMPLEX` object 5344 - height - The requested height 5345 5346 Output Parameters: 5347 + start - The first point at this `height` 5348 - end - One beyond the last point at this `height` 5349 5350 Level: developer 5351 5352 Notes: 5353 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5354 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5355 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5356 5357 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5358 @*/ 5359 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5360 { 5361 DMLabel label; 5362 PetscInt depth, pStart, pEnd; 5363 5364 PetscFunctionBegin; 5365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5366 if (start) { 5367 PetscAssertPointer(start, 3); 5368 *start = 0; 5369 } 5370 if (end) { 5371 PetscAssertPointer(end, 4); 5372 *end = 0; 5373 } 5374 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5375 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5376 if (height < 0) { 5377 if (start) *start = pStart; 5378 if (end) *end = pEnd; 5379 PetscFunctionReturn(PETSC_SUCCESS); 5380 } 5381 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5382 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5383 else PetscCall(DMGetDimension(dm, &depth)); 5384 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5385 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5386 PetscFunctionReturn(PETSC_SUCCESS); 5387 } 5388 5389 /*@ 5390 DMPlexGetPointDepth - Get the `depth` of a given point 5391 5392 Not Collective 5393 5394 Input Parameters: 5395 + dm - The `DMPLEX` object 5396 - point - The point 5397 5398 Output Parameter: 5399 . depth - The depth of the `point` 5400 5401 Level: intermediate 5402 5403 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5404 @*/ 5405 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5406 { 5407 PetscFunctionBegin; 5408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5409 PetscAssertPointer(depth, 3); 5410 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5411 PetscFunctionReturn(PETSC_SUCCESS); 5412 } 5413 5414 /*@ 5415 DMPlexGetPointHeight - Get the `height` of a given point 5416 5417 Not Collective 5418 5419 Input Parameters: 5420 + dm - The `DMPLEX` object 5421 - point - The point 5422 5423 Output Parameter: 5424 . height - The height of the `point` 5425 5426 Level: intermediate 5427 5428 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5429 @*/ 5430 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5431 { 5432 PetscInt n, pDepth; 5433 5434 PetscFunctionBegin; 5435 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5436 PetscAssertPointer(height, 3); 5437 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5438 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5439 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5440 PetscFunctionReturn(PETSC_SUCCESS); 5441 } 5442 5443 /*@ 5444 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5445 5446 Not Collective 5447 5448 Input Parameter: 5449 . dm - The `DMPLEX` object 5450 5451 Output Parameter: 5452 . celltypeLabel - The `DMLabel` recording cell polytope type 5453 5454 Level: developer 5455 5456 Note: 5457 This function will trigger automatica computation of cell types. This can be disabled by calling 5458 `DMCreateLabel`(dm, "celltype") beforehand. 5459 5460 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5461 @*/ 5462 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5463 { 5464 PetscFunctionBegin; 5465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5466 PetscAssertPointer(celltypeLabel, 2); 5467 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5468 *celltypeLabel = dm->celltypeLabel; 5469 PetscFunctionReturn(PETSC_SUCCESS); 5470 } 5471 5472 /*@ 5473 DMPlexGetCellType - Get the polytope type of a given cell 5474 5475 Not Collective 5476 5477 Input Parameters: 5478 + dm - The `DMPLEX` object 5479 - cell - The cell 5480 5481 Output Parameter: 5482 . celltype - The polytope type of the cell 5483 5484 Level: intermediate 5485 5486 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5487 @*/ 5488 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5489 { 5490 DM_Plex *mesh = (DM_Plex *)dm->data; 5491 DMLabel label; 5492 PetscInt ct; 5493 5494 PetscFunctionBegin; 5495 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5496 PetscAssertPointer(celltype, 3); 5497 if (mesh->tr) { 5498 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5499 } else { 5500 PetscInt pStart, pEnd; 5501 5502 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5503 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5504 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5505 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5506 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5507 for (PetscInt p = pStart; p < pEnd; p++) { 5508 PetscCall(DMLabelGetValue(label, p, &ct)); 5509 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5510 } 5511 } 5512 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5513 if (PetscDefined(USE_DEBUG)) { 5514 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5515 PetscCall(DMLabelGetValue(label, cell, &ct)); 5516 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5517 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5518 } 5519 } 5520 PetscFunctionReturn(PETSC_SUCCESS); 5521 } 5522 5523 /*@ 5524 DMPlexSetCellType - Set the polytope type of a given cell 5525 5526 Not Collective 5527 5528 Input Parameters: 5529 + dm - The `DMPLEX` object 5530 . cell - The cell 5531 - celltype - The polytope type of the cell 5532 5533 Level: advanced 5534 5535 Note: 5536 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5537 is executed. This function will override the computed type. However, if automatic classification will not succeed 5538 and a user wants to manually specify all types, the classification must be disabled by calling 5539 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5540 5541 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5542 @*/ 5543 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5544 { 5545 DM_Plex *mesh = (DM_Plex *)dm->data; 5546 DMLabel label; 5547 PetscInt pStart, pEnd; 5548 5549 PetscFunctionBegin; 5550 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5551 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5552 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5553 PetscCall(DMLabelSetValue(label, cell, celltype)); 5554 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5555 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5556 PetscFunctionReturn(PETSC_SUCCESS); 5557 } 5558 5559 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5560 { 5561 PetscSection section; 5562 PetscInt maxHeight; 5563 const char *prefix; 5564 5565 PetscFunctionBegin; 5566 PetscCall(DMClone(dm, cdm)); 5567 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5568 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5569 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5570 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5571 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5572 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5573 PetscCall(DMSetLocalSection(*cdm, section)); 5574 PetscCall(PetscSectionDestroy(§ion)); 5575 5576 PetscCall(DMSetNumFields(*cdm, 1)); 5577 PetscCall(DMCreateDS(*cdm)); 5578 (*cdm)->cloneOpts = PETSC_TRUE; 5579 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5580 PetscFunctionReturn(PETSC_SUCCESS); 5581 } 5582 5583 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5584 { 5585 Vec coordsLocal, cellCoordsLocal; 5586 DM coordsDM, cellCoordsDM; 5587 5588 PetscFunctionBegin; 5589 *field = NULL; 5590 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5591 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5592 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5593 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5594 if (coordsLocal && coordsDM) { 5595 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5596 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5597 } 5598 PetscFunctionReturn(PETSC_SUCCESS); 5599 } 5600 5601 /*@ 5602 DMPlexGetConeSection - Return a section which describes the layout of cone data 5603 5604 Not Collective 5605 5606 Input Parameter: 5607 . dm - The `DMPLEX` object 5608 5609 Output Parameter: 5610 . section - The `PetscSection` object 5611 5612 Level: developer 5613 5614 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5615 @*/ 5616 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5617 { 5618 DM_Plex *mesh = (DM_Plex *)dm->data; 5619 5620 PetscFunctionBegin; 5621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5622 if (section) *section = mesh->coneSection; 5623 PetscFunctionReturn(PETSC_SUCCESS); 5624 } 5625 5626 /*@ 5627 DMPlexGetSupportSection - Return a section which describes the layout of support data 5628 5629 Not Collective 5630 5631 Input Parameter: 5632 . dm - The `DMPLEX` object 5633 5634 Output Parameter: 5635 . section - The `PetscSection` object 5636 5637 Level: developer 5638 5639 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5640 @*/ 5641 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5642 { 5643 DM_Plex *mesh = (DM_Plex *)dm->data; 5644 5645 PetscFunctionBegin; 5646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5647 if (section) *section = mesh->supportSection; 5648 PetscFunctionReturn(PETSC_SUCCESS); 5649 } 5650 5651 /*@C 5652 DMPlexGetCones - Return cone data 5653 5654 Not Collective 5655 5656 Input Parameter: 5657 . dm - The `DMPLEX` object 5658 5659 Output Parameter: 5660 . cones - The cone for each point 5661 5662 Level: developer 5663 5664 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5665 @*/ 5666 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5667 { 5668 DM_Plex *mesh = (DM_Plex *)dm->data; 5669 5670 PetscFunctionBegin; 5671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5672 if (cones) *cones = mesh->cones; 5673 PetscFunctionReturn(PETSC_SUCCESS); 5674 } 5675 5676 /*@C 5677 DMPlexGetConeOrientations - Return cone orientation data 5678 5679 Not Collective 5680 5681 Input Parameter: 5682 . dm - The `DMPLEX` object 5683 5684 Output Parameter: 5685 . coneOrientations - The array of cone orientations for all points 5686 5687 Level: developer 5688 5689 Notes: 5690 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5691 as returned by `DMPlexGetConeOrientation()`. 5692 5693 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5694 5695 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5696 @*/ 5697 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5698 { 5699 DM_Plex *mesh = (DM_Plex *)dm->data; 5700 5701 PetscFunctionBegin; 5702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5703 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5704 PetscFunctionReturn(PETSC_SUCCESS); 5705 } 5706 5707 /* FEM Support */ 5708 5709 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5710 { 5711 PetscInt depth; 5712 5713 PetscFunctionBegin; 5714 PetscCall(DMPlexGetDepth(plex, &depth)); 5715 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5716 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5717 PetscFunctionReturn(PETSC_SUCCESS); 5718 } 5719 5720 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5721 { 5722 PetscInt depth; 5723 5724 PetscFunctionBegin; 5725 PetscCall(DMPlexGetDepth(plex, &depth)); 5726 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5727 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5728 PetscFunctionReturn(PETSC_SUCCESS); 5729 } 5730 5731 /* 5732 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5733 representing a line in the section. 5734 */ 5735 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5736 { 5737 PetscObject obj; 5738 PetscClassId id; 5739 PetscFE fe = NULL; 5740 5741 PetscFunctionBeginHot; 5742 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5743 PetscCall(DMGetField(dm, field, NULL, &obj)); 5744 PetscCall(PetscObjectGetClassId(obj, &id)); 5745 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5746 5747 if (!fe) { 5748 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5749 /* An order k SEM disc has k-1 dofs on an edge */ 5750 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5751 *k = *k / *Nc + 1; 5752 } else { 5753 PetscInt dual_space_size, dim; 5754 PetscDualSpace dsp; 5755 5756 PetscCall(DMGetDimension(dm, &dim)); 5757 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5758 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5759 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5760 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5761 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5762 } 5763 PetscFunctionReturn(PETSC_SUCCESS); 5764 } 5765 5766 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5767 { 5768 PetscFunctionBeginHot; 5769 if (tensor) { 5770 *dof = PetscPowInt(k + 1, dim); 5771 } else { 5772 switch (dim) { 5773 case 1: 5774 *dof = k + 1; 5775 break; 5776 case 2: 5777 *dof = ((k + 1) * (k + 2)) / 2; 5778 break; 5779 case 3: 5780 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5781 break; 5782 default: 5783 *dof = 0; 5784 } 5785 } 5786 PetscFunctionReturn(PETSC_SUCCESS); 5787 } 5788 5789 /*@ 5790 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5791 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5792 section provided (or the section of the `DM`). 5793 5794 Input Parameters: 5795 + dm - The `DM` 5796 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5797 - section - The `PetscSection` to reorder, or `NULL` for the default section 5798 5799 Example: 5800 A typical interpolated single-quad mesh might order points as 5801 .vb 5802 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5803 5804 v4 -- e6 -- v3 5805 | | 5806 e7 c0 e8 5807 | | 5808 v1 -- e5 -- v2 5809 .ve 5810 5811 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5812 dofs in the order of points, e.g., 5813 .vb 5814 c0 -> [0,1,2,3] 5815 v1 -> [4] 5816 ... 5817 e5 -> [8, 9] 5818 .ve 5819 5820 which corresponds to the dofs 5821 .vb 5822 6 10 11 7 5823 13 2 3 15 5824 12 0 1 14 5825 4 8 9 5 5826 .ve 5827 5828 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5829 .vb 5830 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5831 .ve 5832 5833 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5834 .vb 5835 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5836 .ve 5837 5838 Level: developer 5839 5840 Notes: 5841 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5842 degree of the basis. 5843 5844 This is required to run with libCEED. 5845 5846 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5847 @*/ 5848 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5849 { 5850 DMLabel label; 5851 PetscInt dim, depth = -1, eStart = -1, Nf; 5852 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5853 5854 PetscFunctionBegin; 5855 PetscCall(DMGetDimension(dm, &dim)); 5856 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5857 if (point < 0) { 5858 PetscInt sStart, sEnd; 5859 5860 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5861 point = sEnd - sStart ? sStart : point; 5862 } 5863 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5864 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5865 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5866 if (depth == 1) { 5867 eStart = point; 5868 } else if (depth == dim) { 5869 const PetscInt *cone; 5870 5871 PetscCall(DMPlexGetCone(dm, point, &cone)); 5872 if (dim == 2) eStart = cone[0]; 5873 else if (dim == 3) { 5874 const PetscInt *cone2; 5875 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5876 eStart = cone2[0]; 5877 } 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); 5878 } 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); 5879 5880 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5881 for (PetscInt d = 1; d <= dim; d++) { 5882 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5883 PetscInt *perm; 5884 5885 for (f = 0; f < Nf; ++f) { 5886 PetscInt dof; 5887 5888 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5889 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5890 if (!continuous && d < dim) continue; 5891 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5892 size += dof * Nc; 5893 } 5894 PetscCall(PetscMalloc1(size, &perm)); 5895 for (f = 0; f < Nf; ++f) { 5896 switch (d) { 5897 case 1: 5898 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5899 if (!continuous && d < dim) continue; 5900 /* 5901 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5902 We want [ vtx0; edge of length k-1; vtx1 ] 5903 */ 5904 if (continuous) { 5905 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5906 for (i = 0; i < k - 1; i++) 5907 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5908 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5909 foffset = offset; 5910 } else { 5911 PetscInt dof; 5912 5913 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5914 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5915 foffset = offset; 5916 } 5917 break; 5918 case 2: 5919 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5920 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5921 if (!continuous && d < dim) continue; 5922 /* The SEM order is 5923 5924 v_lb, {e_b}, v_rb, 5925 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5926 v_lt, reverse {e_t}, v_rt 5927 */ 5928 if (continuous) { 5929 const PetscInt of = 0; 5930 const PetscInt oeb = of + PetscSqr(k - 1); 5931 const PetscInt oer = oeb + (k - 1); 5932 const PetscInt oet = oer + (k - 1); 5933 const PetscInt oel = oet + (k - 1); 5934 const PetscInt ovlb = oel + (k - 1); 5935 const PetscInt ovrb = ovlb + 1; 5936 const PetscInt ovrt = ovrb + 1; 5937 const PetscInt ovlt = ovrt + 1; 5938 PetscInt o; 5939 5940 /* bottom */ 5941 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5942 for (o = oeb; o < oer; ++o) 5943 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5944 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5945 /* middle */ 5946 for (i = 0; i < k - 1; ++i) { 5947 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5948 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5949 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5950 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5951 } 5952 /* top */ 5953 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5954 for (o = oel - 1; o >= oet; --o) 5955 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5956 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5957 foffset = offset; 5958 } else { 5959 PetscInt dof; 5960 5961 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5962 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5963 foffset = offset; 5964 } 5965 break; 5966 case 3: 5967 /* The original hex closure is 5968 5969 {c, 5970 f_b, f_t, f_f, f_b, f_r, f_l, 5971 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5972 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5973 */ 5974 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5975 if (!continuous && d < dim) continue; 5976 /* The SEM order is 5977 Bottom Slice 5978 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5979 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5980 v_blb, {e_bb}, v_brb, 5981 5982 Middle Slice (j) 5983 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5984 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5985 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5986 5987 Top Slice 5988 v_tlf, {e_tf}, v_trf, 5989 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5990 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5991 */ 5992 if (continuous) { 5993 const PetscInt oc = 0; 5994 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5995 const PetscInt oft = ofb + PetscSqr(k - 1); 5996 const PetscInt off = oft + PetscSqr(k - 1); 5997 const PetscInt ofk = off + PetscSqr(k - 1); 5998 const PetscInt ofr = ofk + PetscSqr(k - 1); 5999 const PetscInt ofl = ofr + PetscSqr(k - 1); 6000 const PetscInt oebl = ofl + PetscSqr(k - 1); 6001 const PetscInt oebb = oebl + (k - 1); 6002 const PetscInt oebr = oebb + (k - 1); 6003 const PetscInt oebf = oebr + (k - 1); 6004 const PetscInt oetf = oebf + (k - 1); 6005 const PetscInt oetr = oetf + (k - 1); 6006 const PetscInt oetb = oetr + (k - 1); 6007 const PetscInt oetl = oetb + (k - 1); 6008 const PetscInt oerf = oetl + (k - 1); 6009 const PetscInt oelf = oerf + (k - 1); 6010 const PetscInt oelb = oelf + (k - 1); 6011 const PetscInt oerb = oelb + (k - 1); 6012 const PetscInt ovblf = oerb + (k - 1); 6013 const PetscInt ovblb = ovblf + 1; 6014 const PetscInt ovbrb = ovblb + 1; 6015 const PetscInt ovbrf = ovbrb + 1; 6016 const PetscInt ovtlf = ovbrf + 1; 6017 const PetscInt ovtrf = ovtlf + 1; 6018 const PetscInt ovtrb = ovtrf + 1; 6019 const PetscInt ovtlb = ovtrb + 1; 6020 PetscInt o, n; 6021 6022 /* Bottom Slice */ 6023 /* bottom */ 6024 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6025 for (o = oetf - 1; o >= oebf; --o) 6026 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6027 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6028 /* middle */ 6029 for (i = 0; i < k - 1; ++i) { 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6031 for (n = 0; n < k - 1; ++n) { 6032 o = ofb + n * (k - 1) + i; 6033 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6034 } 6035 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6036 } 6037 /* top */ 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6039 for (o = oebb; o < oebr; ++o) 6040 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6042 6043 /* Middle Slice */ 6044 for (j = 0; j < k - 1; ++j) { 6045 /* bottom */ 6046 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6047 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6048 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6049 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6050 /* middle */ 6051 for (i = 0; i < k - 1; ++i) { 6052 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6053 for (n = 0; n < k - 1; ++n) 6054 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6055 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6056 } 6057 /* top */ 6058 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6059 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6060 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6061 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6062 } 6063 6064 /* Top Slice */ 6065 /* bottom */ 6066 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6067 for (o = oetf; o < oetr; ++o) 6068 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6069 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6070 /* middle */ 6071 for (i = 0; i < k - 1; ++i) { 6072 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6073 for (n = 0; n < k - 1; ++n) 6074 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6075 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6076 } 6077 /* top */ 6078 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6079 for (o = oetl - 1; o >= oetb; --o) 6080 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6081 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6082 6083 foffset = offset; 6084 } else { 6085 PetscInt dof; 6086 6087 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6088 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6089 foffset = offset; 6090 } 6091 break; 6092 default: 6093 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6094 } 6095 } 6096 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6097 /* Check permutation */ 6098 { 6099 PetscInt *check; 6100 6101 PetscCall(PetscMalloc1(size, &check)); 6102 for (i = 0; i < size; ++i) { 6103 check[i] = -1; 6104 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6105 } 6106 for (i = 0; i < size; ++i) check[perm[i]] = i; 6107 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6108 PetscCall(PetscFree(check)); 6109 } 6110 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6111 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6112 PetscInt *loc_perm; 6113 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6114 for (PetscInt i = 0; i < size; i++) { 6115 loc_perm[i] = perm[i]; 6116 loc_perm[size + i] = size + perm[i]; 6117 } 6118 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6119 } 6120 } 6121 PetscFunctionReturn(PETSC_SUCCESS); 6122 } 6123 6124 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6125 { 6126 PetscDS prob; 6127 PetscInt depth, Nf, h; 6128 DMLabel label; 6129 6130 PetscFunctionBeginHot; 6131 PetscCall(DMGetDS(dm, &prob)); 6132 Nf = prob->Nf; 6133 label = dm->depthLabel; 6134 *dspace = NULL; 6135 if (field < Nf) { 6136 PetscObject disc = prob->disc[field]; 6137 6138 if (disc->classid == PETSCFE_CLASSID) { 6139 PetscDualSpace dsp; 6140 6141 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6142 PetscCall(DMLabelGetNumValues(label, &depth)); 6143 PetscCall(DMLabelGetValue(label, point, &h)); 6144 h = depth - 1 - h; 6145 if (h) { 6146 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6147 } else { 6148 *dspace = dsp; 6149 } 6150 } 6151 } 6152 PetscFunctionReturn(PETSC_SUCCESS); 6153 } 6154 6155 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6156 { 6157 PetscScalar *array; 6158 const PetscScalar *vArray; 6159 const PetscInt *cone, *coneO; 6160 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6161 6162 PetscFunctionBeginHot; 6163 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6164 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6165 PetscCall(DMPlexGetCone(dm, point, &cone)); 6166 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6167 if (!values || !*values) { 6168 if ((point >= pStart) && (point < pEnd)) { 6169 PetscInt dof; 6170 6171 PetscCall(PetscSectionGetDof(section, point, &dof)); 6172 size += dof; 6173 } 6174 for (p = 0; p < numPoints; ++p) { 6175 const PetscInt cp = cone[p]; 6176 PetscInt dof; 6177 6178 if ((cp < pStart) || (cp >= pEnd)) continue; 6179 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6180 size += dof; 6181 } 6182 if (!values) { 6183 if (csize) *csize = size; 6184 PetscFunctionReturn(PETSC_SUCCESS); 6185 } 6186 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6187 } else { 6188 array = *values; 6189 } 6190 size = 0; 6191 PetscCall(VecGetArrayRead(v, &vArray)); 6192 if ((point >= pStart) && (point < pEnd)) { 6193 PetscInt dof, off, d; 6194 const PetscScalar *varr; 6195 6196 PetscCall(PetscSectionGetDof(section, point, &dof)); 6197 PetscCall(PetscSectionGetOffset(section, point, &off)); 6198 varr = PetscSafePointerPlusOffset(vArray, off); 6199 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6200 size += dof; 6201 } 6202 for (p = 0; p < numPoints; ++p) { 6203 const PetscInt cp = cone[p]; 6204 PetscInt o = coneO[p]; 6205 PetscInt dof, off, d; 6206 const PetscScalar *varr; 6207 6208 if ((cp < pStart) || (cp >= pEnd)) continue; 6209 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6210 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6211 varr = PetscSafePointerPlusOffset(vArray, off); 6212 if (o >= 0) { 6213 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6214 } else { 6215 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6216 } 6217 size += dof; 6218 } 6219 PetscCall(VecRestoreArrayRead(v, &vArray)); 6220 if (!*values) { 6221 if (csize) *csize = size; 6222 *values = array; 6223 } else { 6224 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6225 *csize = size; 6226 } 6227 PetscFunctionReturn(PETSC_SUCCESS); 6228 } 6229 6230 /* Compress out points not in the section */ 6231 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6232 { 6233 const PetscInt np = *numPoints; 6234 PetscInt pStart, pEnd, p, q; 6235 6236 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6237 for (p = 0, q = 0; p < np; ++p) { 6238 const PetscInt r = points[p * 2]; 6239 if ((r >= pStart) && (r < pEnd)) { 6240 points[q * 2] = r; 6241 points[q * 2 + 1] = points[p * 2 + 1]; 6242 ++q; 6243 } 6244 } 6245 *numPoints = q; 6246 return PETSC_SUCCESS; 6247 } 6248 6249 /* Compressed closure does not apply closure permutation */ 6250 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6251 { 6252 const PetscInt *cla = NULL; 6253 PetscInt np, *pts = NULL; 6254 6255 PetscFunctionBeginHot; 6256 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6257 if (!ornt && *clPoints) { 6258 PetscInt dof, off; 6259 6260 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6261 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6262 PetscCall(ISGetIndices(*clPoints, &cla)); 6263 np = dof / 2; 6264 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6265 } else { 6266 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6267 PetscCall(CompressPoints_Private(section, &np, pts)); 6268 } 6269 *numPoints = np; 6270 *points = pts; 6271 *clp = cla; 6272 PetscFunctionReturn(PETSC_SUCCESS); 6273 } 6274 6275 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6276 { 6277 PetscFunctionBeginHot; 6278 if (!*clPoints) { 6279 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6280 } else { 6281 PetscCall(ISRestoreIndices(*clPoints, clp)); 6282 } 6283 *numPoints = 0; 6284 *points = NULL; 6285 *clSec = NULL; 6286 *clPoints = NULL; 6287 *clp = NULL; 6288 PetscFunctionReturn(PETSC_SUCCESS); 6289 } 6290 6291 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6292 { 6293 PetscInt offset = 0, p; 6294 const PetscInt **perms = NULL; 6295 const PetscScalar **flips = NULL; 6296 6297 PetscFunctionBeginHot; 6298 *size = 0; 6299 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6300 for (p = 0; p < numPoints; p++) { 6301 const PetscInt point = points[2 * p]; 6302 const PetscInt *perm = perms ? perms[p] : NULL; 6303 const PetscScalar *flip = flips ? flips[p] : NULL; 6304 PetscInt dof, off, d; 6305 const PetscScalar *varr; 6306 6307 PetscCall(PetscSectionGetDof(section, point, &dof)); 6308 PetscCall(PetscSectionGetOffset(section, point, &off)); 6309 varr = PetscSafePointerPlusOffset(vArray, off); 6310 if (clperm) { 6311 if (perm) { 6312 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6313 } else { 6314 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6315 } 6316 if (flip) { 6317 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6318 } 6319 } else { 6320 if (perm) { 6321 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6322 } else { 6323 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6324 } 6325 if (flip) { 6326 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6327 } 6328 } 6329 offset += dof; 6330 } 6331 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6332 *size = offset; 6333 PetscFunctionReturn(PETSC_SUCCESS); 6334 } 6335 6336 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[]) 6337 { 6338 PetscInt offset = 0, f; 6339 6340 PetscFunctionBeginHot; 6341 *size = 0; 6342 for (f = 0; f < numFields; ++f) { 6343 PetscInt p; 6344 const PetscInt **perms = NULL; 6345 const PetscScalar **flips = NULL; 6346 6347 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6348 for (p = 0; p < numPoints; p++) { 6349 const PetscInt point = points[2 * p]; 6350 PetscInt fdof, foff, b; 6351 const PetscScalar *varr; 6352 const PetscInt *perm = perms ? perms[p] : NULL; 6353 const PetscScalar *flip = flips ? flips[p] : NULL; 6354 6355 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6356 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6357 varr = &vArray[foff]; 6358 if (clperm) { 6359 if (perm) { 6360 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6361 } else { 6362 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6363 } 6364 if (flip) { 6365 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6366 } 6367 } else { 6368 if (perm) { 6369 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6370 } else { 6371 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6372 } 6373 if (flip) { 6374 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6375 } 6376 } 6377 offset += fdof; 6378 } 6379 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6380 } 6381 *size = offset; 6382 PetscFunctionReturn(PETSC_SUCCESS); 6383 } 6384 6385 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6386 { 6387 PetscSection clSection; 6388 IS clPoints; 6389 PetscInt *points = NULL; 6390 const PetscInt *clp, *perm = NULL; 6391 PetscInt depth, numFields, numPoints, asize; 6392 6393 PetscFunctionBeginHot; 6394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6395 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6396 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6397 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6398 PetscCall(DMPlexGetDepth(dm, &depth)); 6399 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6400 if (depth == 1 && numFields < 2) { 6401 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6402 PetscFunctionReturn(PETSC_SUCCESS); 6403 } 6404 /* Get points */ 6405 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6406 /* Get sizes */ 6407 asize = 0; 6408 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6409 PetscInt dof; 6410 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6411 asize += dof; 6412 } 6413 if (values) { 6414 const PetscScalar *vArray; 6415 PetscInt size; 6416 6417 if (*values) { 6418 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); 6419 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6420 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6421 PetscCall(VecGetArrayRead(v, &vArray)); 6422 /* Get values */ 6423 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6424 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6425 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6426 /* Cleanup array */ 6427 PetscCall(VecRestoreArrayRead(v, &vArray)); 6428 } 6429 if (csize) *csize = asize; 6430 /* Cleanup points */ 6431 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6432 PetscFunctionReturn(PETSC_SUCCESS); 6433 } 6434 6435 /*@C 6436 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6437 6438 Not collective 6439 6440 Input Parameters: 6441 + dm - The `DM` 6442 . section - The section describing the layout in `v`, or `NULL` to use the default section 6443 . v - The local vector 6444 - point - The point in the `DM` 6445 6446 Input/Output Parameters: 6447 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6448 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6449 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6450 6451 Level: intermediate 6452 6453 Notes: 6454 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6455 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6456 assembly function, and a user may already have allocated storage for this operation. 6457 6458 A typical use could be 6459 .vb 6460 values = NULL; 6461 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6462 for (cl = 0; cl < clSize; ++cl) { 6463 <Compute on closure> 6464 } 6465 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6466 .ve 6467 or 6468 .vb 6469 PetscMalloc1(clMaxSize, &values); 6470 for (p = pStart; p < pEnd; ++p) { 6471 clSize = clMaxSize; 6472 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6473 for (cl = 0; cl < clSize; ++cl) { 6474 <Compute on closure> 6475 } 6476 } 6477 PetscFree(values); 6478 .ve 6479 6480 Fortran Notes: 6481 The `csize` argument is not present in the Fortran binding. 6482 6483 `values` must be declared with 6484 .vb 6485 PetscScalar,dimension(:),pointer :: values 6486 .ve 6487 and it will be allocated internally by PETSc to hold the values returned 6488 6489 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6490 @*/ 6491 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6492 { 6493 PetscFunctionBeginHot; 6494 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6495 PetscFunctionReturn(PETSC_SUCCESS); 6496 } 6497 6498 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6499 { 6500 DMLabel depthLabel; 6501 PetscSection clSection; 6502 IS clPoints; 6503 PetscScalar *array; 6504 const PetscScalar *vArray; 6505 PetscInt *points = NULL; 6506 const PetscInt *clp, *perm = NULL; 6507 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6508 6509 PetscFunctionBeginHot; 6510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6511 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6512 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6513 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6514 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6515 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6516 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6517 if (mdepth == 1 && numFields < 2) { 6518 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6519 PetscFunctionReturn(PETSC_SUCCESS); 6520 } 6521 /* Get points */ 6522 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6523 for (clsize = 0, p = 0; p < Np; p++) { 6524 PetscInt dof; 6525 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6526 clsize += dof; 6527 } 6528 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6529 /* Filter points */ 6530 for (p = 0; p < numPoints * 2; p += 2) { 6531 PetscInt dep; 6532 6533 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6534 if (dep != depth) continue; 6535 points[Np * 2 + 0] = points[p]; 6536 points[Np * 2 + 1] = points[p + 1]; 6537 ++Np; 6538 } 6539 /* Get array */ 6540 if (!values || !*values) { 6541 PetscInt asize = 0, dof; 6542 6543 for (p = 0; p < Np * 2; p += 2) { 6544 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6545 asize += dof; 6546 } 6547 if (!values) { 6548 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6549 if (csize) *csize = asize; 6550 PetscFunctionReturn(PETSC_SUCCESS); 6551 } 6552 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6553 } else { 6554 array = *values; 6555 } 6556 PetscCall(VecGetArrayRead(v, &vArray)); 6557 /* Get values */ 6558 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6559 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6560 /* Cleanup points */ 6561 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6562 /* Cleanup array */ 6563 PetscCall(VecRestoreArrayRead(v, &vArray)); 6564 if (!*values) { 6565 if (csize) *csize = size; 6566 *values = array; 6567 } else { 6568 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6569 *csize = size; 6570 } 6571 PetscFunctionReturn(PETSC_SUCCESS); 6572 } 6573 6574 /*@C 6575 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6576 6577 Not collective 6578 6579 Input Parameters: 6580 + dm - The `DM` 6581 . section - The section describing the layout in `v`, or `NULL` to use the default section 6582 . v - The local vector 6583 . point - The point in the `DM` 6584 . csize - The number of values in the closure, or `NULL` 6585 - values - The array of values 6586 6587 Level: intermediate 6588 6589 Note: 6590 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6591 6592 Fortran Note: 6593 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6594 6595 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6596 @*/ 6597 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6598 { 6599 PetscInt size = 0; 6600 6601 PetscFunctionBegin; 6602 /* Should work without recalculating size */ 6603 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6604 *values = NULL; 6605 PetscFunctionReturn(PETSC_SUCCESS); 6606 } 6607 6608 static inline void add(PetscScalar *x, PetscScalar y) 6609 { 6610 *x += y; 6611 } 6612 static inline void insert(PetscScalar *x, PetscScalar y) 6613 { 6614 *x = y; 6615 } 6616 6617 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[]) 6618 { 6619 PetscInt cdof; /* The number of constraints on this point */ 6620 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6621 PetscScalar *a; 6622 PetscInt off, cind = 0, k; 6623 6624 PetscFunctionBegin; 6625 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6626 PetscCall(PetscSectionGetOffset(section, point, &off)); 6627 a = &array[off]; 6628 if (!cdof || setBC) { 6629 if (clperm) { 6630 if (perm) { 6631 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6632 } else { 6633 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6634 } 6635 } else { 6636 if (perm) { 6637 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6638 } else { 6639 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6640 } 6641 } 6642 } else { 6643 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6644 if (clperm) { 6645 if (perm) { 6646 for (k = 0; k < dof; ++k) { 6647 if ((cind < cdof) && (k == cdofs[cind])) { 6648 ++cind; 6649 continue; 6650 } 6651 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6652 } 6653 } else { 6654 for (k = 0; k < dof; ++k) { 6655 if ((cind < cdof) && (k == cdofs[cind])) { 6656 ++cind; 6657 continue; 6658 } 6659 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6660 } 6661 } 6662 } else { 6663 if (perm) { 6664 for (k = 0; k < dof; ++k) { 6665 if ((cind < cdof) && (k == cdofs[cind])) { 6666 ++cind; 6667 continue; 6668 } 6669 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6670 } 6671 } else { 6672 for (k = 0; k < dof; ++k) { 6673 if ((cind < cdof) && (k == cdofs[cind])) { 6674 ++cind; 6675 continue; 6676 } 6677 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6678 } 6679 } 6680 } 6681 } 6682 PetscFunctionReturn(PETSC_SUCCESS); 6683 } 6684 6685 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[]) 6686 { 6687 PetscInt cdof; /* The number of constraints on this point */ 6688 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6689 PetscScalar *a; 6690 PetscInt off, cind = 0, k; 6691 6692 PetscFunctionBegin; 6693 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6694 PetscCall(PetscSectionGetOffset(section, point, &off)); 6695 a = &array[off]; 6696 if (cdof) { 6697 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6698 if (clperm) { 6699 if (perm) { 6700 for (k = 0; k < dof; ++k) { 6701 if ((cind < cdof) && (k == cdofs[cind])) { 6702 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6703 cind++; 6704 } 6705 } 6706 } else { 6707 for (k = 0; k < dof; ++k) { 6708 if ((cind < cdof) && (k == cdofs[cind])) { 6709 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6710 cind++; 6711 } 6712 } 6713 } 6714 } else { 6715 if (perm) { 6716 for (k = 0; k < dof; ++k) { 6717 if ((cind < cdof) && (k == cdofs[cind])) { 6718 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6719 cind++; 6720 } 6721 } 6722 } else { 6723 for (k = 0; k < dof; ++k) { 6724 if ((cind < cdof) && (k == cdofs[cind])) { 6725 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6726 cind++; 6727 } 6728 } 6729 } 6730 } 6731 } 6732 PetscFunctionReturn(PETSC_SUCCESS); 6733 } 6734 6735 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[]) 6736 { 6737 PetscScalar *a; 6738 PetscInt fdof, foff, fcdof, foffset = *offset; 6739 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6740 PetscInt cind = 0, b; 6741 6742 PetscFunctionBegin; 6743 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6744 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6745 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6746 a = &array[foff]; 6747 if (!fcdof || setBC) { 6748 if (clperm) { 6749 if (perm) { 6750 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6751 } else { 6752 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6753 } 6754 } else { 6755 if (perm) { 6756 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6757 } else { 6758 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6759 } 6760 } 6761 } else { 6762 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6763 if (clperm) { 6764 if (perm) { 6765 for (b = 0; b < fdof; b++) { 6766 if ((cind < fcdof) && (b == fcdofs[cind])) { 6767 ++cind; 6768 continue; 6769 } 6770 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6771 } 6772 } else { 6773 for (b = 0; b < fdof; b++) { 6774 if ((cind < fcdof) && (b == fcdofs[cind])) { 6775 ++cind; 6776 continue; 6777 } 6778 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6779 } 6780 } 6781 } else { 6782 if (perm) { 6783 for (b = 0; b < fdof; b++) { 6784 if ((cind < fcdof) && (b == fcdofs[cind])) { 6785 ++cind; 6786 continue; 6787 } 6788 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6789 } 6790 } else { 6791 for (b = 0; b < fdof; b++) { 6792 if ((cind < fcdof) && (b == fcdofs[cind])) { 6793 ++cind; 6794 continue; 6795 } 6796 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6797 } 6798 } 6799 } 6800 } 6801 *offset += fdof; 6802 PetscFunctionReturn(PETSC_SUCCESS); 6803 } 6804 6805 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[]) 6806 { 6807 PetscScalar *a; 6808 PetscInt fdof, foff, fcdof, foffset = *offset; 6809 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6810 PetscInt Nc, cind = 0, ncind = 0, b; 6811 PetscBool ncSet, fcSet; 6812 6813 PetscFunctionBegin; 6814 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6815 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6816 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6817 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6818 a = &array[foff]; 6819 if (fcdof) { 6820 /* We just override fcdof and fcdofs with Ncc and comps */ 6821 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6822 if (clperm) { 6823 if (perm) { 6824 if (comps) { 6825 for (b = 0; b < fdof; b++) { 6826 ncSet = fcSet = PETSC_FALSE; 6827 if (b % Nc == comps[ncind]) { 6828 ncind = (ncind + 1) % Ncc; 6829 ncSet = PETSC_TRUE; 6830 } 6831 if ((cind < fcdof) && (b == fcdofs[cind])) { 6832 ++cind; 6833 fcSet = PETSC_TRUE; 6834 } 6835 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6836 } 6837 } else { 6838 for (b = 0; b < fdof; b++) { 6839 if ((cind < fcdof) && (b == fcdofs[cind])) { 6840 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6841 ++cind; 6842 } 6843 } 6844 } 6845 } else { 6846 if (comps) { 6847 for (b = 0; b < fdof; b++) { 6848 ncSet = fcSet = PETSC_FALSE; 6849 if (b % Nc == comps[ncind]) { 6850 ncind = (ncind + 1) % Ncc; 6851 ncSet = PETSC_TRUE; 6852 } 6853 if ((cind < fcdof) && (b == fcdofs[cind])) { 6854 ++cind; 6855 fcSet = PETSC_TRUE; 6856 } 6857 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6858 } 6859 } else { 6860 for (b = 0; b < fdof; b++) { 6861 if ((cind < fcdof) && (b == fcdofs[cind])) { 6862 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6863 ++cind; 6864 } 6865 } 6866 } 6867 } 6868 } else { 6869 if (perm) { 6870 if (comps) { 6871 for (b = 0; b < fdof; b++) { 6872 ncSet = fcSet = PETSC_FALSE; 6873 if (b % Nc == comps[ncind]) { 6874 ncind = (ncind + 1) % Ncc; 6875 ncSet = PETSC_TRUE; 6876 } 6877 if ((cind < fcdof) && (b == fcdofs[cind])) { 6878 ++cind; 6879 fcSet = PETSC_TRUE; 6880 } 6881 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6882 } 6883 } else { 6884 for (b = 0; b < fdof; b++) { 6885 if ((cind < fcdof) && (b == fcdofs[cind])) { 6886 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6887 ++cind; 6888 } 6889 } 6890 } 6891 } else { 6892 if (comps) { 6893 for (b = 0; b < fdof; b++) { 6894 ncSet = fcSet = PETSC_FALSE; 6895 if (b % Nc == comps[ncind]) { 6896 ncind = (ncind + 1) % Ncc; 6897 ncSet = PETSC_TRUE; 6898 } 6899 if ((cind < fcdof) && (b == fcdofs[cind])) { 6900 ++cind; 6901 fcSet = PETSC_TRUE; 6902 } 6903 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6904 } 6905 } else { 6906 for (b = 0; b < fdof; b++) { 6907 if ((cind < fcdof) && (b == fcdofs[cind])) { 6908 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6909 ++cind; 6910 } 6911 } 6912 } 6913 } 6914 } 6915 } 6916 *offset += fdof; 6917 PetscFunctionReturn(PETSC_SUCCESS); 6918 } 6919 6920 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6921 { 6922 PetscScalar *array; 6923 const PetscInt *cone, *coneO; 6924 PetscInt pStart, pEnd, p, numPoints, off, dof; 6925 6926 PetscFunctionBeginHot; 6927 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6928 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6929 PetscCall(DMPlexGetCone(dm, point, &cone)); 6930 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6931 PetscCall(VecGetArray(v, &array)); 6932 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6933 const PetscInt cp = !p ? point : cone[p - 1]; 6934 const PetscInt o = !p ? 0 : coneO[p - 1]; 6935 6936 if ((cp < pStart) || (cp >= pEnd)) { 6937 dof = 0; 6938 continue; 6939 } 6940 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6941 /* ADD_VALUES */ 6942 { 6943 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6944 PetscScalar *a; 6945 PetscInt cdof, coff, cind = 0, k; 6946 6947 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6948 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6949 a = &array[coff]; 6950 if (!cdof) { 6951 if (o >= 0) { 6952 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6953 } else { 6954 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6955 } 6956 } else { 6957 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6958 if (o >= 0) { 6959 for (k = 0; k < dof; ++k) { 6960 if ((cind < cdof) && (k == cdofs[cind])) { 6961 ++cind; 6962 continue; 6963 } 6964 a[k] += values[off + k]; 6965 } 6966 } else { 6967 for (k = 0; k < dof; ++k) { 6968 if ((cind < cdof) && (k == cdofs[cind])) { 6969 ++cind; 6970 continue; 6971 } 6972 a[k] += values[off + dof - k - 1]; 6973 } 6974 } 6975 } 6976 } 6977 } 6978 PetscCall(VecRestoreArray(v, &array)); 6979 PetscFunctionReturn(PETSC_SUCCESS); 6980 } 6981 6982 /*@C 6983 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6984 6985 Not collective 6986 6987 Input Parameters: 6988 + dm - The `DM` 6989 . section - The section describing the layout in `v`, or `NULL` to use the default section 6990 . v - The local vector 6991 . point - The point in the `DM` 6992 . values - The array of values 6993 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6994 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6995 6996 Level: intermediate 6997 6998 Note: 6999 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7000 7001 Fortran Note: 7002 `values` must be declared with 7003 .vb 7004 PetscScalar,dimension(:),pointer :: values 7005 .ve 7006 7007 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7008 @*/ 7009 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7010 { 7011 PetscSection clSection; 7012 IS clPoints; 7013 PetscScalar *array; 7014 PetscInt *points = NULL; 7015 const PetscInt *clp, *clperm = NULL; 7016 PetscInt depth, numFields, numPoints, p, clsize; 7017 7018 PetscFunctionBeginHot; 7019 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7020 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7021 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7022 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7023 PetscCall(DMPlexGetDepth(dm, &depth)); 7024 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7025 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7026 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7027 PetscFunctionReturn(PETSC_SUCCESS); 7028 } 7029 /* Get points */ 7030 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7031 for (clsize = 0, p = 0; p < numPoints; p++) { 7032 PetscInt dof; 7033 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7034 clsize += dof; 7035 } 7036 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7037 /* Get array */ 7038 PetscCall(VecGetArray(v, &array)); 7039 /* Get values */ 7040 if (numFields > 0) { 7041 PetscInt offset = 0, f; 7042 for (f = 0; f < numFields; ++f) { 7043 const PetscInt **perms = NULL; 7044 const PetscScalar **flips = NULL; 7045 7046 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7047 switch (mode) { 7048 case INSERT_VALUES: 7049 for (p = 0; p < numPoints; p++) { 7050 const PetscInt point = points[2 * p]; 7051 const PetscInt *perm = perms ? perms[p] : NULL; 7052 const PetscScalar *flip = flips ? flips[p] : NULL; 7053 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7054 } 7055 break; 7056 case INSERT_ALL_VALUES: 7057 for (p = 0; p < numPoints; p++) { 7058 const PetscInt point = points[2 * p]; 7059 const PetscInt *perm = perms ? perms[p] : NULL; 7060 const PetscScalar *flip = flips ? flips[p] : NULL; 7061 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7062 } 7063 break; 7064 case INSERT_BC_VALUES: 7065 for (p = 0; p < numPoints; p++) { 7066 const PetscInt point = points[2 * p]; 7067 const PetscInt *perm = perms ? perms[p] : NULL; 7068 const PetscScalar *flip = flips ? flips[p] : NULL; 7069 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7070 } 7071 break; 7072 case ADD_VALUES: 7073 for (p = 0; p < numPoints; p++) { 7074 const PetscInt point = points[2 * p]; 7075 const PetscInt *perm = perms ? perms[p] : NULL; 7076 const PetscScalar *flip = flips ? flips[p] : NULL; 7077 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7078 } 7079 break; 7080 case ADD_ALL_VALUES: 7081 for (p = 0; p < numPoints; p++) { 7082 const PetscInt point = points[2 * p]; 7083 const PetscInt *perm = perms ? perms[p] : NULL; 7084 const PetscScalar *flip = flips ? flips[p] : NULL; 7085 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7086 } 7087 break; 7088 case ADD_BC_VALUES: 7089 for (p = 0; p < numPoints; p++) { 7090 const PetscInt point = points[2 * p]; 7091 const PetscInt *perm = perms ? perms[p] : NULL; 7092 const PetscScalar *flip = flips ? flips[p] : NULL; 7093 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7094 } 7095 break; 7096 default: 7097 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7098 } 7099 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7100 } 7101 } else { 7102 PetscInt dof, off; 7103 const PetscInt **perms = NULL; 7104 const PetscScalar **flips = NULL; 7105 7106 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7107 switch (mode) { 7108 case INSERT_VALUES: 7109 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7110 const PetscInt point = points[2 * p]; 7111 const PetscInt *perm = perms ? perms[p] : NULL; 7112 const PetscScalar *flip = flips ? flips[p] : NULL; 7113 PetscCall(PetscSectionGetDof(section, point, &dof)); 7114 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7115 } 7116 break; 7117 case INSERT_ALL_VALUES: 7118 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7119 const PetscInt point = points[2 * p]; 7120 const PetscInt *perm = perms ? perms[p] : NULL; 7121 const PetscScalar *flip = flips ? flips[p] : NULL; 7122 PetscCall(PetscSectionGetDof(section, point, &dof)); 7123 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7124 } 7125 break; 7126 case INSERT_BC_VALUES: 7127 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7128 const PetscInt point = points[2 * p]; 7129 const PetscInt *perm = perms ? perms[p] : NULL; 7130 const PetscScalar *flip = flips ? flips[p] : NULL; 7131 PetscCall(PetscSectionGetDof(section, point, &dof)); 7132 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7133 } 7134 break; 7135 case ADD_VALUES: 7136 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7137 const PetscInt point = points[2 * p]; 7138 const PetscInt *perm = perms ? perms[p] : NULL; 7139 const PetscScalar *flip = flips ? flips[p] : NULL; 7140 PetscCall(PetscSectionGetDof(section, point, &dof)); 7141 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7142 } 7143 break; 7144 case ADD_ALL_VALUES: 7145 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7146 const PetscInt point = points[2 * p]; 7147 const PetscInt *perm = perms ? perms[p] : NULL; 7148 const PetscScalar *flip = flips ? flips[p] : NULL; 7149 PetscCall(PetscSectionGetDof(section, point, &dof)); 7150 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7151 } 7152 break; 7153 case ADD_BC_VALUES: 7154 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7155 const PetscInt point = points[2 * p]; 7156 const PetscInt *perm = perms ? perms[p] : NULL; 7157 const PetscScalar *flip = flips ? flips[p] : NULL; 7158 PetscCall(PetscSectionGetDof(section, point, &dof)); 7159 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7160 } 7161 break; 7162 default: 7163 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7164 } 7165 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7166 } 7167 /* Cleanup points */ 7168 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7169 /* Cleanup array */ 7170 PetscCall(VecRestoreArray(v, &array)); 7171 PetscFunctionReturn(PETSC_SUCCESS); 7172 } 7173 7174 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7175 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7176 { 7177 PetscFunctionBegin; 7178 *contains = PETSC_TRUE; 7179 if (label) { 7180 PetscInt fdof; 7181 7182 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7183 if (!*contains) { 7184 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7185 *offset += fdof; 7186 PetscFunctionReturn(PETSC_SUCCESS); 7187 } 7188 } 7189 PetscFunctionReturn(PETSC_SUCCESS); 7190 } 7191 7192 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7193 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) 7194 { 7195 PetscSection clSection; 7196 IS clPoints; 7197 PetscScalar *array; 7198 PetscInt *points = NULL; 7199 const PetscInt *clp; 7200 PetscInt numFields, numPoints, p; 7201 PetscInt offset = 0, f; 7202 7203 PetscFunctionBeginHot; 7204 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7205 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7206 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7207 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7208 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7209 /* Get points */ 7210 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7211 /* Get array */ 7212 PetscCall(VecGetArray(v, &array)); 7213 /* Get values */ 7214 for (f = 0; f < numFields; ++f) { 7215 const PetscInt **perms = NULL; 7216 const PetscScalar **flips = NULL; 7217 PetscBool contains; 7218 7219 if (!fieldActive[f]) { 7220 for (p = 0; p < numPoints * 2; p += 2) { 7221 PetscInt fdof; 7222 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7223 offset += fdof; 7224 } 7225 continue; 7226 } 7227 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7228 switch (mode) { 7229 case INSERT_VALUES: 7230 for (p = 0; p < numPoints; p++) { 7231 const PetscInt point = points[2 * p]; 7232 const PetscInt *perm = perms ? perms[p] : NULL; 7233 const PetscScalar *flip = flips ? flips[p] : NULL; 7234 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7235 if (!contains) continue; 7236 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7237 } 7238 break; 7239 case INSERT_ALL_VALUES: 7240 for (p = 0; p < numPoints; p++) { 7241 const PetscInt point = points[2 * p]; 7242 const PetscInt *perm = perms ? perms[p] : NULL; 7243 const PetscScalar *flip = flips ? flips[p] : NULL; 7244 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7245 if (!contains) continue; 7246 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7247 } 7248 break; 7249 case INSERT_BC_VALUES: 7250 for (p = 0; p < numPoints; p++) { 7251 const PetscInt point = points[2 * p]; 7252 const PetscInt *perm = perms ? perms[p] : NULL; 7253 const PetscScalar *flip = flips ? flips[p] : NULL; 7254 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7255 if (!contains) continue; 7256 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7257 } 7258 break; 7259 case ADD_VALUES: 7260 for (p = 0; p < numPoints; p++) { 7261 const PetscInt point = points[2 * p]; 7262 const PetscInt *perm = perms ? perms[p] : NULL; 7263 const PetscScalar *flip = flips ? flips[p] : NULL; 7264 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7265 if (!contains) continue; 7266 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7267 } 7268 break; 7269 case ADD_ALL_VALUES: 7270 for (p = 0; p < numPoints; p++) { 7271 const PetscInt point = points[2 * p]; 7272 const PetscInt *perm = perms ? perms[p] : NULL; 7273 const PetscScalar *flip = flips ? flips[p] : NULL; 7274 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7275 if (!contains) continue; 7276 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7277 } 7278 break; 7279 default: 7280 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7281 } 7282 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7283 } 7284 /* Cleanup points */ 7285 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7286 /* Cleanup array */ 7287 PetscCall(VecRestoreArray(v, &array)); 7288 PetscFunctionReturn(PETSC_SUCCESS); 7289 } 7290 7291 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7292 { 7293 PetscMPIInt rank; 7294 PetscInt i, j; 7295 7296 PetscFunctionBegin; 7297 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7298 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7299 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7300 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7301 numCIndices = numCIndices ? numCIndices : numRIndices; 7302 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7303 for (i = 0; i < numRIndices; i++) { 7304 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7305 for (j = 0; j < numCIndices; j++) { 7306 #if defined(PETSC_USE_COMPLEX) 7307 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7308 #else 7309 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7310 #endif 7311 } 7312 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7313 } 7314 PetscFunctionReturn(PETSC_SUCCESS); 7315 } 7316 7317 /* 7318 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7319 7320 Input Parameters: 7321 + section - The section for this data layout 7322 . islocal - Is the section (and thus indices being requested) local or global? 7323 . point - The point contributing dofs with these indices 7324 . off - The global offset of this point 7325 . loff - The local offset of each field 7326 . setBC - The flag determining whether to include indices of boundary values 7327 . perm - A permutation of the dofs on this point, or NULL 7328 - indperm - A permutation of the entire indices array, or NULL 7329 7330 Output Parameter: 7331 . indices - Indices for dofs on this point 7332 7333 Level: developer 7334 7335 Note: The indices could be local or global, depending on the value of 'off'. 7336 */ 7337 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7338 { 7339 PetscInt dof; /* The number of unknowns on this point */ 7340 PetscInt cdof; /* The number of constraints on this point */ 7341 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7342 PetscInt cind = 0, k; 7343 7344 PetscFunctionBegin; 7345 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7346 PetscCall(PetscSectionGetDof(section, point, &dof)); 7347 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7348 if (!cdof || setBC) { 7349 for (k = 0; k < dof; ++k) { 7350 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7351 const PetscInt ind = indperm ? indperm[preind] : preind; 7352 7353 indices[ind] = off + k; 7354 } 7355 } else { 7356 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7357 for (k = 0; k < dof; ++k) { 7358 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7359 const PetscInt ind = indperm ? indperm[preind] : preind; 7360 7361 if ((cind < cdof) && (k == cdofs[cind])) { 7362 /* Insert check for returning constrained indices */ 7363 indices[ind] = -(off + k + 1); 7364 ++cind; 7365 } else { 7366 indices[ind] = off + k - (islocal ? 0 : cind); 7367 } 7368 } 7369 } 7370 *loff += dof; 7371 PetscFunctionReturn(PETSC_SUCCESS); 7372 } 7373 7374 /* 7375 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7376 7377 Input Parameters: 7378 + section - a section (global or local) 7379 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7380 . point - point within section 7381 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7382 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7383 . setBC - identify constrained (boundary condition) points via involution. 7384 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7385 . permsoff - offset 7386 - indperm - index permutation 7387 7388 Output Parameter: 7389 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7390 . indices - array to hold indices (as defined by section) of each dof associated with point 7391 7392 Notes: 7393 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7394 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7395 in the local vector. 7396 7397 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7398 significant). It is invalid to call with a global section and setBC=true. 7399 7400 Developer Note: 7401 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7402 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7403 offset could be obtained from the section instead of passing it explicitly as we do now. 7404 7405 Example: 7406 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7407 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7408 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7409 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. 7410 7411 Level: developer 7412 */ 7413 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[]) 7414 { 7415 PetscInt numFields, foff, f; 7416 7417 PetscFunctionBegin; 7418 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7419 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7420 for (f = 0, foff = 0; f < numFields; ++f) { 7421 PetscInt fdof, cfdof; 7422 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7423 PetscInt cind = 0, b; 7424 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7425 7426 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7427 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7428 if (!cfdof || setBC) { 7429 for (b = 0; b < fdof; ++b) { 7430 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7431 const PetscInt ind = indperm ? indperm[preind] : preind; 7432 7433 indices[ind] = off + foff + b; 7434 } 7435 } else { 7436 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7437 for (b = 0; b < fdof; ++b) { 7438 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7439 const PetscInt ind = indperm ? indperm[preind] : preind; 7440 7441 if ((cind < cfdof) && (b == fcdofs[cind])) { 7442 indices[ind] = -(off + foff + b + 1); 7443 ++cind; 7444 } else { 7445 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7446 } 7447 } 7448 } 7449 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7450 foffs[f] += fdof; 7451 } 7452 PetscFunctionReturn(PETSC_SUCCESS); 7453 } 7454 7455 /* 7456 This version believes the globalSection offsets for each field, rather than just the point offset 7457 7458 . foffs - The offset into 'indices' for each field, since it is segregated by field 7459 7460 Notes: 7461 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7462 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7463 */ 7464 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7465 { 7466 PetscInt numFields, foff, f; 7467 7468 PetscFunctionBegin; 7469 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7470 for (f = 0; f < numFields; ++f) { 7471 PetscInt fdof, cfdof; 7472 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7473 PetscInt cind = 0, b; 7474 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7475 7476 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7477 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7478 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7479 if (!cfdof) { 7480 for (b = 0; b < fdof; ++b) { 7481 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7482 const PetscInt ind = indperm ? indperm[preind] : preind; 7483 7484 indices[ind] = foff + b; 7485 } 7486 } else { 7487 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7488 for (b = 0; b < fdof; ++b) { 7489 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7490 const PetscInt ind = indperm ? indperm[preind] : preind; 7491 7492 if ((cind < cfdof) && (b == fcdofs[cind])) { 7493 indices[ind] = -(foff + b + 1); 7494 ++cind; 7495 } else { 7496 indices[ind] = foff + b - cind; 7497 } 7498 } 7499 } 7500 foffs[f] += fdof; 7501 } 7502 PetscFunctionReturn(PETSC_SUCCESS); 7503 } 7504 7505 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7506 { 7507 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7508 7509 PetscFunctionBegin; 7510 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7511 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7512 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7513 for (PetscInt p = 0; p < nPoints; p++) { 7514 PetscInt b = pnts[2 * p]; 7515 PetscInt bSecDof = 0, bOff; 7516 PetscInt cSecDof = 0; 7517 PetscSection indices_section; 7518 7519 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7520 if (!bSecDof) continue; 7521 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7522 indices_section = cSecDof > 0 ? cSec : section; 7523 if (numFields) { 7524 PetscInt fStart[32], fEnd[32]; 7525 7526 fStart[0] = 0; 7527 fEnd[0] = 0; 7528 for (PetscInt f = 0; f < numFields; f++) { 7529 PetscInt fDof = 0; 7530 7531 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7532 fStart[f + 1] = fStart[f] + fDof; 7533 fEnd[f + 1] = fStart[f + 1]; 7534 } 7535 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7536 // only apply permutations on one side 7537 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7538 for (PetscInt f = 0; f < numFields; f++) { 7539 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7540 } 7541 } else { 7542 PetscInt bEnd = 0; 7543 7544 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7545 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7546 7547 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7548 } 7549 } 7550 PetscFunctionReturn(PETSC_SUCCESS); 7551 } 7552 7553 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[]) 7554 { 7555 Mat cMat; 7556 PetscSection aSec, cSec; 7557 IS aIS; 7558 PetscInt aStart = -1, aEnd = -1; 7559 PetscInt sStart = -1, sEnd = -1; 7560 PetscInt cStart = -1, cEnd = -1; 7561 const PetscInt *anchors; 7562 PetscInt numFields, p; 7563 PetscInt newNumPoints = 0, newNumIndices = 0; 7564 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7565 PetscInt oldOffsets[32]; 7566 PetscInt newOffsets[32]; 7567 PetscInt oldOffsetsCopy[32]; 7568 PetscInt newOffsetsCopy[32]; 7569 PetscScalar *modMat = NULL; 7570 PetscBool anyConstrained = PETSC_FALSE; 7571 7572 PetscFunctionBegin; 7573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7574 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7575 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7576 7577 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7578 /* if there are point-to-point constraints */ 7579 if (aSec) { 7580 PetscCall(PetscArrayzero(newOffsets, 32)); 7581 PetscCall(PetscArrayzero(oldOffsets, 32)); 7582 PetscCall(ISGetIndices(aIS, &anchors)); 7583 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7584 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7585 /* figure out how many points are going to be in the new element matrix 7586 * (we allow double counting, because it's all just going to be summed 7587 * into the global matrix anyway) */ 7588 for (p = 0; p < 2 * numPoints; p += 2) { 7589 PetscInt b = points[p]; 7590 PetscInt bDof = 0, bSecDof = 0; 7591 7592 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7593 if (!bSecDof) continue; 7594 7595 for (PetscInt f = 0; f < numFields; f++) { 7596 PetscInt fDof = 0; 7597 7598 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7599 oldOffsets[f + 1] += fDof; 7600 } 7601 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7602 if (bDof) { 7603 /* this point is constrained */ 7604 /* it is going to be replaced by its anchors */ 7605 PetscInt bOff, q; 7606 7607 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7608 for (q = 0; q < bDof; q++) { 7609 PetscInt a = anchors[bOff + q]; 7610 PetscInt aDof = 0; 7611 7612 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7613 if (aDof) { 7614 anyConstrained = PETSC_TRUE; 7615 newNumPoints += 1; 7616 } 7617 newNumIndices += aDof; 7618 for (PetscInt f = 0; f < numFields; ++f) { 7619 PetscInt fDof = 0; 7620 7621 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7622 newOffsets[f + 1] += fDof; 7623 } 7624 } 7625 } else { 7626 /* this point is not constrained */ 7627 newNumPoints++; 7628 newNumIndices += bSecDof; 7629 for (PetscInt f = 0; f < numFields; ++f) { 7630 PetscInt fDof; 7631 7632 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7633 newOffsets[f + 1] += fDof; 7634 } 7635 } 7636 } 7637 } 7638 if (!anyConstrained) { 7639 if (outNumPoints) *outNumPoints = 0; 7640 if (outNumIndices) *outNumIndices = 0; 7641 if (outPoints) *outPoints = NULL; 7642 if (outMat) *outMat = NULL; 7643 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7644 PetscFunctionReturn(PETSC_SUCCESS); 7645 } 7646 7647 if (outNumPoints) *outNumPoints = newNumPoints; 7648 if (outNumIndices) *outNumIndices = newNumIndices; 7649 7650 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7651 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7652 7653 if (!outPoints && !outMat) { 7654 if (offsets) { 7655 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7656 } 7657 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7658 PetscFunctionReturn(PETSC_SUCCESS); 7659 } 7660 7661 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7662 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7663 7664 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7665 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7666 7667 /* output arrays */ 7668 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7669 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7670 7671 // get the new Points 7672 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7673 PetscInt b = points[2 * p]; 7674 PetscInt bDof = 0, bSecDof = 0, bOff; 7675 7676 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7677 if (!bSecDof) continue; 7678 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7679 if (bDof) { 7680 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7681 for (PetscInt q = 0; q < bDof; q++) { 7682 PetscInt a = anchors[bOff + q], aDof = 0; 7683 7684 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7685 if (aDof) { 7686 newPoints[2 * newP] = a; 7687 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7688 newP++; 7689 } 7690 } 7691 } else { 7692 newPoints[2 * newP] = b; 7693 newPoints[2 * newP + 1] = points[2 * p + 1]; 7694 newP++; 7695 } 7696 } 7697 7698 if (outMat) { 7699 PetscScalar *tmpMat; 7700 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7701 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7702 7703 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7704 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7705 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7706 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7707 7708 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7709 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7710 7711 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7712 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7713 7714 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7715 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7716 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7717 // for each field, insert the anchor modification into modMat 7718 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7719 PetscInt fStart = oldOffsets[f]; 7720 PetscInt fNewStart = newOffsets[f]; 7721 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7722 PetscInt b = points[2 * p]; 7723 PetscInt bDof = 0, bSecDof = 0, bOff; 7724 7725 if (b >= sStart && b < sEnd) { 7726 if (numFields) { 7727 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7728 } else { 7729 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7730 } 7731 } 7732 if (!bSecDof) continue; 7733 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7734 if (bDof) { 7735 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7736 for (PetscInt q = 0; q < bDof; q++, newP++) { 7737 PetscInt a = anchors[bOff + q], aDof = 0; 7738 7739 if (a >= sStart && a < sEnd) { 7740 if (numFields) { 7741 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7742 } else { 7743 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7744 } 7745 } 7746 if (aDof) { 7747 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7748 for (PetscInt d = 0; d < bSecDof; d++) { 7749 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7750 } 7751 } 7752 oNew += aDof; 7753 } 7754 } else { 7755 // Insert the identity matrix in this block 7756 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7757 oNew += bSecDof; 7758 newP++; 7759 } 7760 o += bSecDof; 7761 } 7762 } 7763 7764 *outMat = modMat; 7765 7766 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7767 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7768 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7769 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7770 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7771 } 7772 PetscCall(ISRestoreIndices(aIS, &anchors)); 7773 7774 /* output */ 7775 if (outPoints) { 7776 *outPoints = newPoints; 7777 } else { 7778 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7779 } 7780 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7781 PetscFunctionReturn(PETSC_SUCCESS); 7782 } 7783 7784 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) 7785 { 7786 PetscScalar *modMat = NULL; 7787 PetscInt newNumIndices = -1; 7788 7789 PetscFunctionBegin; 7790 /* 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. 7791 modMat is that matrix C */ 7792 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7793 if (outNumIndices) *outNumIndices = newNumIndices; 7794 if (modMat) { 7795 const PetscScalar *newValues = values; 7796 7797 if (multiplyRight) { 7798 PetscScalar *newNewValues = NULL; 7799 PetscBLASInt M, N, K; 7800 PetscScalar a = 1.0, b = 0.0; 7801 7802 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); 7803 7804 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7805 PetscCall(PetscBLASIntCast(numRows, &N)); 7806 PetscCall(PetscBLASIntCast(numIndices, &K)); 7807 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7808 // row-major to column-major conversion, right multiplication becomes left multiplication 7809 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7810 numCols = newNumIndices; 7811 newValues = newNewValues; 7812 } 7813 7814 if (multiplyLeft) { 7815 PetscScalar *newNewValues = NULL; 7816 PetscBLASInt M, N, K; 7817 PetscScalar a = 1.0, b = 0.0; 7818 7819 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); 7820 7821 PetscCall(PetscBLASIntCast(numCols, &M)); 7822 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7823 PetscCall(PetscBLASIntCast(numIndices, &K)); 7824 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7825 // row-major to column-major conversion, left multiplication becomes right multiplication 7826 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7827 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7828 newValues = newNewValues; 7829 } 7830 *outValues = (PetscScalar *)newValues; 7831 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7832 } 7833 PetscFunctionReturn(PETSC_SUCCESS); 7834 } 7835 7836 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) 7837 { 7838 PetscFunctionBegin; 7839 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7840 PetscFunctionReturn(PETSC_SUCCESS); 7841 } 7842 7843 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7844 { 7845 /* Closure ordering */ 7846 PetscSection clSection; 7847 IS clPoints; 7848 const PetscInt *clp; 7849 PetscInt *points; 7850 PetscInt Ncl, Ni = 0; 7851 7852 PetscFunctionBeginHot; 7853 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7854 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7855 PetscInt dof; 7856 7857 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7858 Ni += dof; 7859 } 7860 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7861 *closureSize = Ni; 7862 PetscFunctionReturn(PETSC_SUCCESS); 7863 } 7864 7865 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) 7866 { 7867 /* Closure ordering */ 7868 PetscSection clSection; 7869 IS clPoints; 7870 const PetscInt *clp; 7871 PetscInt *points; 7872 const PetscInt *clperm = NULL; 7873 /* Dof permutation and sign flips */ 7874 const PetscInt **perms[32] = {NULL}; 7875 const PetscScalar **flips[32] = {NULL}; 7876 PetscScalar *valCopy = NULL; 7877 /* Hanging node constraints */ 7878 PetscInt *pointsC = NULL; 7879 PetscScalar *valuesC = NULL; 7880 PetscInt NclC, NiC; 7881 7882 PetscInt *idx; 7883 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7884 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7885 PetscInt idxStart, idxEnd; 7886 PetscInt nRows, nCols; 7887 7888 PetscFunctionBeginHot; 7889 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7890 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7891 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7892 PetscAssertPointer(numRows, 6); 7893 PetscAssertPointer(numCols, 7); 7894 if (indices) PetscAssertPointer(indices, 8); 7895 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7896 if (values) PetscAssertPointer(values, 10); 7897 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7898 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7899 PetscCall(PetscArrayzero(offsets, 32)); 7900 /* 1) Get points in closure */ 7901 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7902 if (useClPerm) { 7903 PetscInt depth, clsize; 7904 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7905 for (clsize = 0, p = 0; p < Ncl; p++) { 7906 PetscInt dof; 7907 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7908 clsize += dof; 7909 } 7910 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7911 } 7912 /* 2) Get number of indices on these points and field offsets from section */ 7913 for (p = 0; p < Ncl * 2; p += 2) { 7914 PetscInt dof, fdof; 7915 7916 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7917 for (f = 0; f < Nf; ++f) { 7918 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7919 offsets[f + 1] += fdof; 7920 } 7921 Ni += dof; 7922 } 7923 if (*numRows == -1) *numRows = Ni; 7924 if (*numCols == -1) *numCols = Ni; 7925 nRows = *numRows; 7926 nCols = *numCols; 7927 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7928 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7929 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7930 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7931 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7932 for (f = 0; f < PetscMax(1, Nf); ++f) { 7933 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7934 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7935 /* may need to apply sign changes to the element matrix */ 7936 if (values && flips[f]) { 7937 PetscInt foffset = offsets[f]; 7938 7939 for (p = 0; p < Ncl; ++p) { 7940 PetscInt pnt = points[2 * p], fdof; 7941 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7942 7943 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7944 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7945 if (flip) { 7946 PetscInt i, j, k; 7947 7948 if (!valCopy) { 7949 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7950 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7951 *values = valCopy; 7952 } 7953 for (i = 0; i < fdof; ++i) { 7954 PetscScalar fval = flip[i]; 7955 7956 if (multiplyRight) { 7957 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7958 } 7959 if (multiplyLeft) { 7960 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7961 } 7962 } 7963 } 7964 foffset += fdof; 7965 } 7966 } 7967 } 7968 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7969 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7970 if (NclC) { 7971 if (multiplyRight) *numCols = NiC; 7972 if (multiplyLeft) *numRows = NiC; 7973 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7974 for (f = 0; f < PetscMax(1, Nf); ++f) { 7975 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7976 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7977 } 7978 for (f = 0; f < PetscMax(1, Nf); ++f) { 7979 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7980 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7981 } 7982 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7983 Ncl = NclC; 7984 Ni = NiC; 7985 points = pointsC; 7986 if (values) *values = valuesC; 7987 } 7988 /* 5) Calculate indices */ 7989 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7990 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 7991 if (Nf) { 7992 PetscInt idxOff; 7993 PetscBool useFieldOffsets; 7994 7995 if (outOffsets) { 7996 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7997 } 7998 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7999 if (useFieldOffsets) { 8000 for (p = 0; p < Ncl; ++p) { 8001 const PetscInt pnt = points[p * 2]; 8002 8003 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8004 } 8005 } else { 8006 for (p = 0; p < Ncl; ++p) { 8007 const PetscInt pnt = points[p * 2]; 8008 8009 if (pnt < idxStart || pnt >= idxEnd) continue; 8010 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8011 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8012 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8013 * global section. */ 8014 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8015 } 8016 } 8017 } else { 8018 PetscInt off = 0, idxOff; 8019 8020 for (p = 0; p < Ncl; ++p) { 8021 const PetscInt pnt = points[p * 2]; 8022 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8023 8024 if (pnt < idxStart || pnt >= idxEnd) continue; 8025 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8026 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8027 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8028 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8029 } 8030 } 8031 /* 6) Cleanup */ 8032 for (f = 0; f < PetscMax(1, Nf); ++f) { 8033 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8034 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8035 } 8036 if (NclC) { 8037 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8038 } else { 8039 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8040 } 8041 8042 if (indices) *indices = idx; 8043 PetscFunctionReturn(PETSC_SUCCESS); 8044 } 8045 8046 /*@C 8047 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8048 8049 Not collective 8050 8051 Input Parameters: 8052 + dm - The `DM` 8053 . section - The `PetscSection` describing the points (a local section) 8054 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8055 . point - The point defining the closure 8056 - useClPerm - Use the closure point permutation if available 8057 8058 Output Parameters: 8059 + numIndices - The number of dof indices in the closure of point with the input sections 8060 . indices - The dof indices 8061 . outOffsets - Array to write the field offsets into, or `NULL` 8062 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8063 8064 Level: advanced 8065 8066 Notes: 8067 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8068 8069 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8070 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8071 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8072 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8073 indices (with the above semantics) are implied. 8074 8075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8076 `PetscSection`, `DMGetGlobalSection()` 8077 @*/ 8078 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8079 { 8080 PetscInt numRows = -1, numCols = -1; 8081 8082 PetscFunctionBeginHot; 8083 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8084 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8085 *numIndices = numRows; 8086 PetscFunctionReturn(PETSC_SUCCESS); 8087 } 8088 8089 /*@C 8090 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8091 8092 Not collective 8093 8094 Input Parameters: 8095 + dm - The `DM` 8096 . section - The `PetscSection` describing the points (a local section) 8097 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8098 . point - The point defining the closure 8099 - useClPerm - Use the closure point permutation if available 8100 8101 Output Parameters: 8102 + numIndices - The number of dof indices in the closure of point with the input sections 8103 . indices - The dof indices 8104 . outOffsets - Array to write the field offsets into, or `NULL` 8105 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8106 8107 Level: advanced 8108 8109 Notes: 8110 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8111 8112 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8113 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8114 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8115 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8116 indices (with the above semantics) are implied. 8117 8118 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8119 @*/ 8120 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8121 { 8122 PetscFunctionBegin; 8123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8124 PetscAssertPointer(indices, 7); 8125 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8126 PetscFunctionReturn(PETSC_SUCCESS); 8127 } 8128 8129 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8130 { 8131 DM_Plex *mesh = (DM_Plex *)dm->data; 8132 PetscInt *indices; 8133 PetscInt numIndices; 8134 const PetscScalar *valuesOrig = values; 8135 PetscErrorCode ierr; 8136 8137 PetscFunctionBegin; 8138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8139 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8140 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8141 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8142 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8143 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8144 8145 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8146 8147 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8148 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8149 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8150 if (ierr) { 8151 PetscMPIInt rank; 8152 8153 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8154 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8155 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8156 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8157 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8158 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8159 } 8160 if (mesh->printFEM > 1) { 8161 PetscInt i; 8162 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8163 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8164 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8165 } 8166 8167 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8168 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8169 PetscFunctionReturn(PETSC_SUCCESS); 8170 } 8171 8172 /*@C 8173 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8174 8175 Not collective 8176 8177 Input Parameters: 8178 + dm - The `DM` 8179 . section - The section describing the layout in `v`, or `NULL` to use the default section 8180 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8181 . A - The matrix 8182 . point - The point in the `DM` 8183 . values - The array of values 8184 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8185 8186 Level: intermediate 8187 8188 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8189 @*/ 8190 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8191 { 8192 PetscFunctionBegin; 8193 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8194 PetscFunctionReturn(PETSC_SUCCESS); 8195 } 8196 8197 /*@C 8198 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8199 8200 Not collective 8201 8202 Input Parameters: 8203 + dmRow - The `DM` for the row fields 8204 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8205 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8206 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8207 . dmCol - The `DM` for the column fields 8208 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8209 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8210 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8211 . A - The matrix 8212 . point - The point in the `DM` 8213 . values - The array of values 8214 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8215 8216 Level: intermediate 8217 8218 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8219 @*/ 8220 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) 8221 { 8222 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8223 PetscInt *indicesRow, *indicesCol; 8224 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8225 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8226 8227 PetscErrorCode ierr; 8228 8229 PetscFunctionBegin; 8230 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8231 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8232 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8233 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8234 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8235 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8236 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8237 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8238 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8239 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8240 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8241 8242 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8243 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8244 valuesV1 = valuesV0; 8245 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8246 valuesV2 = valuesV1; 8247 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8248 8249 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8250 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8251 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8252 if (ierr) { 8253 PetscMPIInt rank; 8254 8255 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8256 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8257 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8258 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8259 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8260 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8261 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8262 } 8263 8264 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8265 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8266 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8267 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8268 PetscFunctionReturn(PETSC_SUCCESS); 8269 } 8270 8271 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8272 { 8273 DM_Plex *mesh = (DM_Plex *)dmf->data; 8274 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8275 PetscInt *cpoints = NULL; 8276 PetscInt *findices, *cindices; 8277 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8278 PetscInt foffsets[32], coffsets[32]; 8279 DMPolytopeType ct; 8280 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8281 PetscErrorCode ierr; 8282 8283 PetscFunctionBegin; 8284 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8285 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8286 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8287 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8288 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8289 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8290 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8291 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8292 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8293 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8294 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8295 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8296 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8297 PetscCall(PetscArrayzero(foffsets, 32)); 8298 PetscCall(PetscArrayzero(coffsets, 32)); 8299 /* Column indices */ 8300 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8301 maxFPoints = numCPoints; 8302 /* Compress out points not in the section */ 8303 /* TODO: Squeeze out points with 0 dof as well */ 8304 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8305 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8306 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8307 cpoints[q * 2] = cpoints[p]; 8308 cpoints[q * 2 + 1] = cpoints[p + 1]; 8309 ++q; 8310 } 8311 } 8312 numCPoints = q; 8313 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8314 PetscInt fdof; 8315 8316 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8317 if (!dof) continue; 8318 for (f = 0; f < numFields; ++f) { 8319 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8320 coffsets[f + 1] += fdof; 8321 } 8322 numCIndices += dof; 8323 } 8324 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8325 /* Row indices */ 8326 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8327 { 8328 DMPlexTransform tr; 8329 DMPolytopeType *rct; 8330 PetscInt *rsize, *rcone, *rornt, Nt; 8331 8332 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8333 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8334 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8335 numSubcells = rsize[Nt - 1]; 8336 PetscCall(DMPlexTransformDestroy(&tr)); 8337 } 8338 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8339 for (r = 0, q = 0; r < numSubcells; ++r) { 8340 /* TODO Map from coarse to fine cells */ 8341 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8342 /* Compress out points not in the section */ 8343 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8344 for (p = 0; p < numFPoints * 2; p += 2) { 8345 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8346 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8347 if (!dof) continue; 8348 for (s = 0; s < q; ++s) 8349 if (fpoints[p] == ftotpoints[s * 2]) break; 8350 if (s < q) continue; 8351 ftotpoints[q * 2] = fpoints[p]; 8352 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8353 ++q; 8354 } 8355 } 8356 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8357 } 8358 numFPoints = q; 8359 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8360 PetscInt fdof; 8361 8362 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8363 if (!dof) continue; 8364 for (f = 0; f < numFields; ++f) { 8365 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8366 foffsets[f + 1] += fdof; 8367 } 8368 numFIndices += dof; 8369 } 8370 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8371 8372 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8373 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8374 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8375 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8376 if (numFields) { 8377 const PetscInt **permsF[32] = {NULL}; 8378 const PetscInt **permsC[32] = {NULL}; 8379 8380 for (f = 0; f < numFields; f++) { 8381 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8382 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8383 } 8384 for (p = 0; p < numFPoints; p++) { 8385 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8386 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8387 } 8388 for (p = 0; p < numCPoints; p++) { 8389 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8390 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8391 } 8392 for (f = 0; f < numFields; f++) { 8393 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8394 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8395 } 8396 } else { 8397 const PetscInt **permsF = NULL; 8398 const PetscInt **permsC = NULL; 8399 8400 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8401 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8402 for (p = 0, off = 0; p < numFPoints; p++) { 8403 const PetscInt *perm = permsF ? permsF[p] : NULL; 8404 8405 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8406 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8407 } 8408 for (p = 0, off = 0; p < numCPoints; p++) { 8409 const PetscInt *perm = permsC ? permsC[p] : NULL; 8410 8411 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8412 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8413 } 8414 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8415 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8416 } 8417 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8418 /* TODO: flips */ 8419 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8420 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8421 if (ierr) { 8422 PetscMPIInt rank; 8423 8424 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8425 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8426 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8427 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8428 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8429 } 8430 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8431 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8432 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8433 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8434 PetscFunctionReturn(PETSC_SUCCESS); 8435 } 8436 8437 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8438 { 8439 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8440 PetscInt *cpoints = NULL; 8441 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8442 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8443 DMPolytopeType ct; 8444 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8445 8446 PetscFunctionBegin; 8447 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8448 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8449 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8450 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8451 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8452 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8453 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8454 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8455 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8456 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8457 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8458 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8459 /* Column indices */ 8460 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8461 maxFPoints = numCPoints; 8462 /* Compress out points not in the section */ 8463 /* TODO: Squeeze out points with 0 dof as well */ 8464 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8465 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8466 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8467 cpoints[q * 2] = cpoints[p]; 8468 cpoints[q * 2 + 1] = cpoints[p + 1]; 8469 ++q; 8470 } 8471 } 8472 numCPoints = q; 8473 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8474 PetscInt fdof; 8475 8476 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8477 if (!dof) continue; 8478 for (f = 0; f < numFields; ++f) { 8479 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8480 coffsets[f + 1] += fdof; 8481 } 8482 numCIndices += dof; 8483 } 8484 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8485 /* Row indices */ 8486 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8487 { 8488 DMPlexTransform tr; 8489 DMPolytopeType *rct; 8490 PetscInt *rsize, *rcone, *rornt, Nt; 8491 8492 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8493 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8494 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8495 numSubcells = rsize[Nt - 1]; 8496 PetscCall(DMPlexTransformDestroy(&tr)); 8497 } 8498 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8499 for (r = 0, q = 0; r < numSubcells; ++r) { 8500 /* TODO Map from coarse to fine cells */ 8501 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8502 /* Compress out points not in the section */ 8503 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8504 for (p = 0; p < numFPoints * 2; p += 2) { 8505 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8506 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8507 if (!dof) continue; 8508 for (s = 0; s < q; ++s) 8509 if (fpoints[p] == ftotpoints[s * 2]) break; 8510 if (s < q) continue; 8511 ftotpoints[q * 2] = fpoints[p]; 8512 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8513 ++q; 8514 } 8515 } 8516 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8517 } 8518 numFPoints = q; 8519 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8520 PetscInt fdof; 8521 8522 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8523 if (!dof) continue; 8524 for (f = 0; f < numFields; ++f) { 8525 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8526 foffsets[f + 1] += fdof; 8527 } 8528 numFIndices += dof; 8529 } 8530 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8531 8532 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8533 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8534 if (numFields) { 8535 const PetscInt **permsF[32] = {NULL}; 8536 const PetscInt **permsC[32] = {NULL}; 8537 8538 for (f = 0; f < numFields; f++) { 8539 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8540 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8541 } 8542 for (p = 0; p < numFPoints; p++) { 8543 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8544 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8545 } 8546 for (p = 0; p < numCPoints; p++) { 8547 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8548 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8549 } 8550 for (f = 0; f < numFields; f++) { 8551 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8552 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8553 } 8554 } else { 8555 const PetscInt **permsF = NULL; 8556 const PetscInt **permsC = NULL; 8557 8558 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8559 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8560 for (p = 0, off = 0; p < numFPoints; p++) { 8561 const PetscInt *perm = permsF ? permsF[p] : NULL; 8562 8563 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8564 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8565 } 8566 for (p = 0, off = 0; p < numCPoints; p++) { 8567 const PetscInt *perm = permsC ? permsC[p] : NULL; 8568 8569 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8570 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8571 } 8572 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8573 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8574 } 8575 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8576 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8577 PetscFunctionReturn(PETSC_SUCCESS); 8578 } 8579 8580 /*@ 8581 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8582 8583 Input Parameter: 8584 . dm - The `DMPLEX` object 8585 8586 Output Parameter: 8587 . cellHeight - The height of a cell 8588 8589 Level: developer 8590 8591 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8592 @*/ 8593 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8594 { 8595 DM_Plex *mesh = (DM_Plex *)dm->data; 8596 8597 PetscFunctionBegin; 8598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8599 PetscAssertPointer(cellHeight, 2); 8600 *cellHeight = mesh->vtkCellHeight; 8601 PetscFunctionReturn(PETSC_SUCCESS); 8602 } 8603 8604 /*@ 8605 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8606 8607 Input Parameters: 8608 + dm - The `DMPLEX` object 8609 - cellHeight - The height of a cell 8610 8611 Level: developer 8612 8613 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8614 @*/ 8615 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8616 { 8617 DM_Plex *mesh = (DM_Plex *)dm->data; 8618 8619 PetscFunctionBegin; 8620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8621 mesh->vtkCellHeight = cellHeight; 8622 PetscFunctionReturn(PETSC_SUCCESS); 8623 } 8624 8625 /*@ 8626 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8627 8628 Input Parameters: 8629 + dm - The `DMPLEX` object 8630 - ct - The `DMPolytopeType` of the cell 8631 8632 Output Parameters: 8633 + start - The first cell of this type, or `NULL` 8634 - end - The upper bound on this celltype, or `NULL` 8635 8636 Level: advanced 8637 8638 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8639 @*/ 8640 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8641 { 8642 DM_Plex *mesh = (DM_Plex *)dm->data; 8643 DMLabel label; 8644 PetscInt pStart, pEnd; 8645 8646 PetscFunctionBegin; 8647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8648 if (start) { 8649 PetscAssertPointer(start, 3); 8650 *start = 0; 8651 } 8652 if (end) { 8653 PetscAssertPointer(end, 4); 8654 *end = 0; 8655 } 8656 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8657 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8658 if (mesh->tr) { 8659 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8660 } else { 8661 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8662 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8663 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8664 } 8665 PetscFunctionReturn(PETSC_SUCCESS); 8666 } 8667 8668 /*@ 8669 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8670 8671 Input Parameters: 8672 + dm - The `DMPLEX` object 8673 - depth - The depth for the given point stratum 8674 8675 Output Parameter: 8676 . gsize - The global number of points in the stratum 8677 8678 Level: advanced 8679 8680 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8681 @*/ 8682 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8683 { 8684 PetscSF sf; 8685 const PetscInt *leaves; 8686 PetscInt Nl, loc, start, end, lsize = 0; 8687 8688 PetscFunctionBegin; 8689 PetscCall(DMGetPointSF(dm, &sf)); 8690 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8691 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8692 for (PetscInt p = start; p < end; ++p) { 8693 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8694 if (loc < 0) ++lsize; 8695 } 8696 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8697 PetscFunctionReturn(PETSC_SUCCESS); 8698 } 8699 8700 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8701 { 8702 PetscSection section, globalSection; 8703 PetscInt *numbers, p; 8704 8705 PetscFunctionBegin; 8706 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8707 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8708 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8709 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8710 PetscCall(PetscSectionSetUp(section)); 8711 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8712 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8713 for (p = pStart; p < pEnd; ++p) { 8714 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8715 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8716 else numbers[p - pStart] += shift; 8717 } 8718 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8719 if (globalSize) { 8720 PetscLayout layout; 8721 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8722 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8723 PetscCall(PetscLayoutDestroy(&layout)); 8724 } 8725 PetscCall(PetscSectionDestroy(§ion)); 8726 PetscCall(PetscSectionDestroy(&globalSection)); 8727 PetscFunctionReturn(PETSC_SUCCESS); 8728 } 8729 8730 /*@ 8731 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8732 8733 Input Parameters: 8734 + dm - The `DMPLEX` object 8735 - includeAll - Whether to include all cells, or just the simplex and box cells 8736 8737 Output Parameter: 8738 . globalCellNumbers - Global cell numbers for all cells on this process 8739 8740 Level: developer 8741 8742 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8743 @*/ 8744 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8745 { 8746 PetscInt cellHeight, cStart, cEnd; 8747 8748 PetscFunctionBegin; 8749 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8750 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8751 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8752 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8753 PetscFunctionReturn(PETSC_SUCCESS); 8754 } 8755 8756 /*@ 8757 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8758 8759 Input Parameter: 8760 . dm - The `DMPLEX` object 8761 8762 Output Parameter: 8763 . globalCellNumbers - Global cell numbers for all cells on this process 8764 8765 Level: developer 8766 8767 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8768 @*/ 8769 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8770 { 8771 DM_Plex *mesh = (DM_Plex *)dm->data; 8772 8773 PetscFunctionBegin; 8774 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8775 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8776 *globalCellNumbers = mesh->globalCellNumbers; 8777 PetscFunctionReturn(PETSC_SUCCESS); 8778 } 8779 8780 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8781 { 8782 PetscInt vStart, vEnd; 8783 8784 PetscFunctionBegin; 8785 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8786 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8787 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8788 PetscFunctionReturn(PETSC_SUCCESS); 8789 } 8790 8791 /*@ 8792 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8793 8794 Input Parameter: 8795 . dm - The `DMPLEX` object 8796 8797 Output Parameter: 8798 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8799 8800 Level: developer 8801 8802 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8803 @*/ 8804 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8805 { 8806 DM_Plex *mesh = (DM_Plex *)dm->data; 8807 8808 PetscFunctionBegin; 8809 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8810 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8811 *globalVertexNumbers = mesh->globalVertexNumbers; 8812 PetscFunctionReturn(PETSC_SUCCESS); 8813 } 8814 8815 /*@ 8816 DMPlexCreatePointNumbering - Create a global numbering for all points. 8817 8818 Collective 8819 8820 Input Parameter: 8821 . dm - The `DMPLEX` object 8822 8823 Output Parameter: 8824 . globalPointNumbers - Global numbers for all points on this process 8825 8826 Level: developer 8827 8828 Notes: 8829 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8830 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8831 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8832 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8833 8834 The partitioned mesh is 8835 ``` 8836 (2)--0--(3)--1--(4) (1)--0--(2) 8837 ``` 8838 and its global numbering is 8839 ``` 8840 (3)--0--(4)--1--(5)--2--(6) 8841 ``` 8842 Then the global numbering is provided as 8843 ``` 8844 [0] Number of indices in set 5 8845 [0] 0 0 8846 [0] 1 1 8847 [0] 2 3 8848 [0] 3 4 8849 [0] 4 -6 8850 [1] Number of indices in set 3 8851 [1] 0 2 8852 [1] 1 5 8853 [1] 2 6 8854 ``` 8855 8856 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8857 @*/ 8858 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8859 { 8860 IS nums[4]; 8861 PetscInt depths[4], gdepths[4], starts[4]; 8862 PetscInt depth, d, shift = 0; 8863 PetscBool empty = PETSC_FALSE; 8864 8865 PetscFunctionBegin; 8866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8867 PetscCall(DMPlexGetDepth(dm, &depth)); 8868 // For unstratified meshes use dim instead of depth 8869 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8870 // If any stratum is empty, we must mark all empty 8871 for (d = 0; d <= depth; ++d) { 8872 PetscInt end; 8873 8874 depths[d] = depth - d; 8875 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8876 if (!(starts[d] - end)) empty = PETSC_TRUE; 8877 } 8878 if (empty) 8879 for (d = 0; d <= depth; ++d) { 8880 depths[d] = -1; 8881 starts[d] = -1; 8882 } 8883 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8884 PetscCallMPI(MPIU_Allreduce(depths, gdepths, (PetscMPIInt)(depth + 1), MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8885 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]); 8886 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8887 for (d = 0; d <= depth; ++d) { 8888 PetscInt pStart, pEnd, gsize; 8889 8890 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8891 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8892 shift += gsize; 8893 } 8894 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8895 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8896 PetscFunctionReturn(PETSC_SUCCESS); 8897 } 8898 8899 /*@ 8900 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8901 8902 Collective 8903 8904 Input Parameter: 8905 . dm - The `DMPLEX` object 8906 8907 Output Parameter: 8908 . globalEdgeNumbers - Global numbers for all edges on this process 8909 8910 Level: developer 8911 8912 Notes: 8913 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). 8914 8915 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8916 @*/ 8917 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8918 { 8919 PetscSF sf; 8920 PetscInt eStart, eEnd; 8921 8922 PetscFunctionBegin; 8923 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8924 PetscCall(DMGetPointSF(dm, &sf)); 8925 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8926 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8927 PetscFunctionReturn(PETSC_SUCCESS); 8928 } 8929 8930 /*@ 8931 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8932 8933 Input Parameter: 8934 . dm - The `DMPLEX` object 8935 8936 Output Parameter: 8937 . ranks - The rank field 8938 8939 Options Database Key: 8940 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8941 8942 Level: intermediate 8943 8944 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8945 @*/ 8946 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8947 { 8948 DM rdm; 8949 PetscFE fe; 8950 PetscScalar *r; 8951 PetscMPIInt rank; 8952 DMPolytopeType ct; 8953 PetscInt dim, cStart, cEnd, c; 8954 PetscBool simplex; 8955 8956 PetscFunctionBeginUser; 8957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8958 PetscAssertPointer(ranks, 2); 8959 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8960 PetscCall(DMClone(dm, &rdm)); 8961 PetscCall(DMGetDimension(rdm, &dim)); 8962 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8963 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8964 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8965 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8966 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8967 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8968 PetscCall(PetscFEDestroy(&fe)); 8969 PetscCall(DMCreateDS(rdm)); 8970 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8971 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8972 PetscCall(VecGetArray(*ranks, &r)); 8973 for (c = cStart; c < cEnd; ++c) { 8974 PetscScalar *lr; 8975 8976 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8977 if (lr) *lr = rank; 8978 } 8979 PetscCall(VecRestoreArray(*ranks, &r)); 8980 PetscCall(DMDestroy(&rdm)); 8981 PetscFunctionReturn(PETSC_SUCCESS); 8982 } 8983 8984 /*@ 8985 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8986 8987 Input Parameters: 8988 + dm - The `DMPLEX` 8989 - label - The `DMLabel` 8990 8991 Output Parameter: 8992 . val - The label value field 8993 8994 Options Database Key: 8995 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8996 8997 Level: intermediate 8998 8999 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9000 @*/ 9001 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9002 { 9003 DM rdm, plex; 9004 Vec lval; 9005 PetscSection section; 9006 PetscFE fe; 9007 PetscScalar *v; 9008 PetscInt dim, pStart, pEnd, p, cStart; 9009 DMPolytopeType ct; 9010 char name[PETSC_MAX_PATH_LEN]; 9011 const char *lname, *prefix; 9012 9013 PetscFunctionBeginUser; 9014 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9015 PetscAssertPointer(label, 2); 9016 PetscAssertPointer(val, 3); 9017 PetscCall(DMClone(dm, &rdm)); 9018 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9019 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9020 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9021 PetscCall(DMDestroy(&plex)); 9022 PetscCall(DMGetDimension(rdm, &dim)); 9023 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9024 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9025 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9026 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9027 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9028 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9029 PetscCall(PetscFEDestroy(&fe)); 9030 PetscCall(DMCreateDS(rdm)); 9031 PetscCall(DMCreateGlobalVector(rdm, val)); 9032 PetscCall(DMCreateLocalVector(rdm, &lval)); 9033 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9034 PetscCall(DMGetLocalSection(rdm, §ion)); 9035 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9036 PetscCall(VecGetArray(lval, &v)); 9037 for (p = pStart; p < pEnd; ++p) { 9038 PetscInt cval, dof, off; 9039 9040 PetscCall(PetscSectionGetDof(section, p, &dof)); 9041 if (!dof) continue; 9042 PetscCall(DMLabelGetValue(label, p, &cval)); 9043 PetscCall(PetscSectionGetOffset(section, p, &off)); 9044 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9045 } 9046 PetscCall(VecRestoreArray(lval, &v)); 9047 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9048 PetscCall(VecDestroy(&lval)); 9049 PetscCall(DMDestroy(&rdm)); 9050 PetscFunctionReturn(PETSC_SUCCESS); 9051 } 9052 9053 /*@ 9054 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9055 9056 Input Parameter: 9057 . dm - The `DMPLEX` object 9058 9059 Level: developer 9060 9061 Notes: 9062 This is a useful diagnostic when creating meshes programmatically. 9063 9064 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9065 9066 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9067 @*/ 9068 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9069 { 9070 PetscSection coneSection, supportSection; 9071 const PetscInt *cone, *support; 9072 PetscInt coneSize, c, supportSize, s; 9073 PetscInt pStart, pEnd, p, pp, csize, ssize; 9074 PetscBool storagecheck = PETSC_TRUE; 9075 9076 PetscFunctionBegin; 9077 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9078 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9079 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9080 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9081 /* Check that point p is found in the support of its cone points, and vice versa */ 9082 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9083 for (p = pStart; p < pEnd; ++p) { 9084 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9085 PetscCall(DMPlexGetCone(dm, p, &cone)); 9086 for (c = 0; c < coneSize; ++c) { 9087 PetscBool dup = PETSC_FALSE; 9088 PetscInt d; 9089 for (d = c - 1; d >= 0; --d) { 9090 if (cone[c] == cone[d]) { 9091 dup = PETSC_TRUE; 9092 break; 9093 } 9094 } 9095 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9096 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9097 for (s = 0; s < supportSize; ++s) { 9098 if (support[s] == p) break; 9099 } 9100 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9101 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9102 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9103 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9104 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9105 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9106 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9107 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]); 9108 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9109 } 9110 } 9111 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9112 if (p != pp) { 9113 storagecheck = PETSC_FALSE; 9114 continue; 9115 } 9116 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9117 PetscCall(DMPlexGetSupport(dm, p, &support)); 9118 for (s = 0; s < supportSize; ++s) { 9119 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9120 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9121 for (c = 0; c < coneSize; ++c) { 9122 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9123 if (cone[c] != pp) { 9124 c = 0; 9125 break; 9126 } 9127 if (cone[c] == p) break; 9128 } 9129 if (c >= coneSize) { 9130 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9131 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9132 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9133 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9134 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9135 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9136 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9137 } 9138 } 9139 } 9140 if (storagecheck) { 9141 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9142 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9143 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9144 } 9145 PetscFunctionReturn(PETSC_SUCCESS); 9146 } 9147 9148 /* 9149 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. 9150 */ 9151 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9152 { 9153 DMPolytopeType cct; 9154 PetscInt ptpoints[4]; 9155 const PetscInt *cone, *ccone, *ptcone; 9156 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9157 9158 PetscFunctionBegin; 9159 *unsplit = 0; 9160 switch (ct) { 9161 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9162 ptpoints[npt++] = c; 9163 break; 9164 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9165 PetscCall(DMPlexGetCone(dm, c, &cone)); 9166 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9167 for (cp = 0; cp < coneSize; ++cp) { 9168 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9169 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9170 } 9171 break; 9172 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9173 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9174 PetscCall(DMPlexGetCone(dm, c, &cone)); 9175 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9176 for (cp = 0; cp < coneSize; ++cp) { 9177 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9178 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9179 for (ccp = 0; ccp < cconeSize; ++ccp) { 9180 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9181 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9182 PetscInt p; 9183 for (p = 0; p < npt; ++p) 9184 if (ptpoints[p] == ccone[ccp]) break; 9185 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9186 } 9187 } 9188 } 9189 break; 9190 default: 9191 break; 9192 } 9193 for (pt = 0; pt < npt; ++pt) { 9194 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9195 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9196 } 9197 PetscFunctionReturn(PETSC_SUCCESS); 9198 } 9199 9200 /*@ 9201 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9202 9203 Input Parameters: 9204 + dm - The `DMPLEX` object 9205 - cellHeight - Normally 0 9206 9207 Level: developer 9208 9209 Notes: 9210 This is a useful diagnostic when creating meshes programmatically. 9211 Currently applicable only to homogeneous simplex or tensor meshes. 9212 9213 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9214 9215 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9216 @*/ 9217 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9218 { 9219 DMPlexInterpolatedFlag interp; 9220 DMPolytopeType ct; 9221 PetscInt vStart, vEnd, cStart, cEnd, c; 9222 9223 PetscFunctionBegin; 9224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9225 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9226 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9227 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9228 for (c = cStart; c < cEnd; ++c) { 9229 PetscInt *closure = NULL; 9230 PetscInt coneSize, closureSize, cl, Nv = 0; 9231 9232 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9233 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9234 if (interp == DMPLEX_INTERPOLATED_FULL) { 9235 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9236 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)); 9237 } 9238 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9239 for (cl = 0; cl < closureSize * 2; cl += 2) { 9240 const PetscInt p = closure[cl]; 9241 if ((p >= vStart) && (p < vEnd)) ++Nv; 9242 } 9243 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9244 /* Special Case: Tensor faces with identified vertices */ 9245 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9246 PetscInt unsplit; 9247 9248 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9249 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9250 } 9251 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)); 9252 } 9253 PetscFunctionReturn(PETSC_SUCCESS); 9254 } 9255 9256 /*@ 9257 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9258 9259 Collective 9260 9261 Input Parameters: 9262 + dm - The `DMPLEX` object 9263 - cellHeight - Normally 0 9264 9265 Level: developer 9266 9267 Notes: 9268 This is a useful diagnostic when creating meshes programmatically. 9269 This routine is only relevant for meshes that are fully interpolated across all ranks. 9270 It will error out if a partially interpolated mesh is given on some rank. 9271 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9272 9273 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9274 9275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9276 @*/ 9277 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9278 { 9279 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9280 DMPlexInterpolatedFlag interpEnum; 9281 9282 PetscFunctionBegin; 9283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9284 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9285 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9286 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9287 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9288 PetscFunctionReturn(PETSC_SUCCESS); 9289 } 9290 9291 PetscCall(DMGetDimension(dm, &dim)); 9292 PetscCall(DMPlexGetDepth(dm, &depth)); 9293 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9294 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9295 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9296 for (c = cStart; c < cEnd; ++c) { 9297 const PetscInt *cone, *ornt, *faceSizes, *faces; 9298 const DMPolytopeType *faceTypes; 9299 DMPolytopeType ct; 9300 PetscInt numFaces, coneSize, f; 9301 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9302 9303 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9304 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9305 if (unsplit) continue; 9306 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9307 PetscCall(DMPlexGetCone(dm, c, &cone)); 9308 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9309 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9310 for (cl = 0; cl < closureSize * 2; cl += 2) { 9311 const PetscInt p = closure[cl]; 9312 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9313 } 9314 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9315 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); 9316 for (f = 0; f < numFaces; ++f) { 9317 DMPolytopeType fct; 9318 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9319 9320 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9321 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9322 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9323 const PetscInt p = fclosure[cl]; 9324 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9325 } 9326 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]); 9327 for (v = 0; v < fnumCorners; ++v) { 9328 if (fclosure[v] != faces[fOff + v]) { 9329 PetscInt v1; 9330 9331 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9332 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9333 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9334 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9335 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9336 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]); 9337 } 9338 } 9339 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9340 fOff += faceSizes[f]; 9341 } 9342 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9343 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9344 } 9345 } 9346 PetscFunctionReturn(PETSC_SUCCESS); 9347 } 9348 9349 /*@ 9350 DMPlexCheckGeometry - Check the geometry of mesh cells 9351 9352 Input Parameter: 9353 . dm - The `DMPLEX` object 9354 9355 Level: developer 9356 9357 Notes: 9358 This is a useful diagnostic when creating meshes programmatically. 9359 9360 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9361 9362 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9363 @*/ 9364 PetscErrorCode DMPlexCheckGeometry(DM dm) 9365 { 9366 Vec coordinates; 9367 PetscReal detJ, J[9], refVol = 1.0; 9368 PetscReal vol; 9369 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9370 9371 PetscFunctionBegin; 9372 PetscCall(DMGetDimension(dm, &dim)); 9373 PetscCall(DMGetCoordinateDim(dm, &dE)); 9374 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9375 PetscCall(DMPlexGetDepth(dm, &depth)); 9376 for (d = 0; d < dim; ++d) refVol *= 2.0; 9377 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9378 /* Make sure local coordinates are created, because that step is collective */ 9379 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9380 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9381 for (c = cStart; c < cEnd; ++c) { 9382 DMPolytopeType ct; 9383 PetscInt unsplit; 9384 PetscBool ignoreZeroVol = PETSC_FALSE; 9385 9386 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9387 switch (ct) { 9388 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9389 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9390 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9391 ignoreZeroVol = PETSC_TRUE; 9392 break; 9393 default: 9394 break; 9395 } 9396 switch (ct) { 9397 case DM_POLYTOPE_TRI_PRISM: 9398 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9399 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9400 case DM_POLYTOPE_PYRAMID: 9401 continue; 9402 default: 9403 break; 9404 } 9405 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9406 if (unsplit) continue; 9407 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9408 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); 9409 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9410 /* This should work with periodicity since DG coordinates should be used */ 9411 if (depth > 1) { 9412 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9413 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); 9414 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9415 } 9416 } 9417 PetscFunctionReturn(PETSC_SUCCESS); 9418 } 9419 9420 /*@ 9421 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9422 9423 Collective 9424 9425 Input Parameters: 9426 + dm - The `DMPLEX` object 9427 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9428 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9429 9430 Level: developer 9431 9432 Notes: 9433 This is mainly intended for debugging/testing purposes. 9434 9435 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9436 9437 Extra roots can come from periodic cuts, where additional points appear on the boundary 9438 9439 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9440 @*/ 9441 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9442 { 9443 PetscInt l, nleaves, nroots, overlap; 9444 const PetscInt *locals; 9445 const PetscSFNode *remotes; 9446 PetscBool distributed; 9447 MPI_Comm comm; 9448 PetscMPIInt rank; 9449 9450 PetscFunctionBegin; 9451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9452 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9453 else pointSF = dm->sf; 9454 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9455 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9456 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9457 { 9458 PetscMPIInt mpiFlag; 9459 9460 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9461 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9462 } 9463 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9464 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9465 if (!distributed) { 9466 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); 9467 PetscFunctionReturn(PETSC_SUCCESS); 9468 } 9469 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); 9470 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9471 9472 /* Check SF graph is compatible with DMPlex chart */ 9473 { 9474 PetscInt pStart, pEnd, maxLeaf; 9475 9476 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9477 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9478 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9479 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9480 } 9481 9482 /* Check Point SF has no local points referenced */ 9483 for (l = 0; l < nleaves; l++) { 9484 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); 9485 } 9486 9487 /* Check there are no cells in interface */ 9488 if (!overlap) { 9489 PetscInt cellHeight, cStart, cEnd; 9490 9491 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9492 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9493 for (l = 0; l < nleaves; ++l) { 9494 const PetscInt point = locals ? locals[l] : l; 9495 9496 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9497 } 9498 } 9499 9500 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9501 { 9502 const PetscInt *rootdegree; 9503 9504 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9505 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9506 for (l = 0; l < nleaves; ++l) { 9507 const PetscInt point = locals ? locals[l] : l; 9508 const PetscInt *cone; 9509 PetscInt coneSize, c, idx; 9510 9511 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9512 PetscCall(DMPlexGetCone(dm, point, &cone)); 9513 for (c = 0; c < coneSize; ++c) { 9514 if (!rootdegree[cone[c]]) { 9515 if (locals) { 9516 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9517 } else { 9518 idx = (cone[c] < nleaves) ? cone[c] : -1; 9519 } 9520 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9521 } 9522 } 9523 } 9524 } 9525 PetscFunctionReturn(PETSC_SUCCESS); 9526 } 9527 9528 /*@ 9529 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9530 9531 Collective 9532 9533 Input Parameter: 9534 . dm - The `DMPLEX` object 9535 9536 Level: developer 9537 9538 Notes: 9539 This is mainly intended for debugging/testing purposes. 9540 9541 Other cell types which are disconnected would be caught by the symmetry and face checks. 9542 9543 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9544 9545 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9546 @*/ 9547 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9548 { 9549 PetscInt pStart, pEnd, vStart, vEnd; 9550 9551 PetscFunctionBegin; 9552 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9553 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9554 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9555 for (PetscInt v = vStart; v < vEnd; ++v) { 9556 PetscInt suppSize; 9557 9558 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9559 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9560 } 9561 PetscFunctionReturn(PETSC_SUCCESS); 9562 } 9563 9564 /*@ 9565 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9566 9567 Input Parameter: 9568 . dm - The `DMPLEX` object 9569 9570 Level: developer 9571 9572 Notes: 9573 This is a useful diagnostic when creating meshes programmatically. 9574 9575 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9576 9577 Currently does not include `DMPlexCheckCellShape()`. 9578 9579 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9580 @*/ 9581 PetscErrorCode DMPlexCheck(DM dm) 9582 { 9583 PetscInt cellHeight; 9584 9585 PetscFunctionBegin; 9586 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9587 PetscCall(DMPlexCheckSymmetry(dm)); 9588 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9589 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9590 PetscCall(DMPlexCheckGeometry(dm)); 9591 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9592 PetscCall(DMPlexCheckInterfaceCones(dm)); 9593 PetscCall(DMPlexCheckOrphanVertices(dm)); 9594 PetscFunctionReturn(PETSC_SUCCESS); 9595 } 9596 9597 typedef struct cell_stats { 9598 PetscReal min, max, sum, squaresum; 9599 PetscInt count; 9600 } cell_stats_t; 9601 9602 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9603 { 9604 PetscInt i, N = *len; 9605 9606 for (i = 0; i < N; i++) { 9607 cell_stats_t *A = (cell_stats_t *)a; 9608 cell_stats_t *B = (cell_stats_t *)b; 9609 9610 B->min = PetscMin(A->min, B->min); 9611 B->max = PetscMax(A->max, B->max); 9612 B->sum += A->sum; 9613 B->squaresum += A->squaresum; 9614 B->count += A->count; 9615 } 9616 } 9617 9618 /*@ 9619 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9620 9621 Collective 9622 9623 Input Parameters: 9624 + dm - The `DMPLEX` object 9625 . output - If true, statistics will be displayed on `stdout` 9626 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9627 9628 Level: developer 9629 9630 Notes: 9631 This is mainly intended for debugging/testing purposes. 9632 9633 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9634 9635 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9636 @*/ 9637 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9638 { 9639 DM dmCoarse; 9640 cell_stats_t stats, globalStats; 9641 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9642 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9643 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9644 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9645 PetscMPIInt rank, size; 9646 9647 PetscFunctionBegin; 9648 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9649 stats.min = PETSC_MAX_REAL; 9650 stats.max = PETSC_MIN_REAL; 9651 stats.sum = stats.squaresum = 0.; 9652 stats.count = 0; 9653 9654 PetscCallMPI(MPI_Comm_size(comm, &size)); 9655 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9656 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9657 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9658 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9659 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9660 for (c = cStart; c < cEnd; c++) { 9661 PetscInt i; 9662 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9663 9664 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9665 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9666 for (i = 0; i < PetscSqr(cdim); ++i) { 9667 frobJ += J[i] * J[i]; 9668 frobInvJ += invJ[i] * invJ[i]; 9669 } 9670 cond2 = frobJ * frobInvJ; 9671 cond = PetscSqrtReal(cond2); 9672 9673 stats.min = PetscMin(stats.min, cond); 9674 stats.max = PetscMax(stats.max, cond); 9675 stats.sum += cond; 9676 stats.squaresum += cond2; 9677 stats.count++; 9678 if (output && cond > limit) { 9679 PetscSection coordSection; 9680 Vec coordsLocal; 9681 PetscScalar *coords = NULL; 9682 PetscInt Nv, d, clSize, cl, *closure = NULL; 9683 9684 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9685 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9686 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9687 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9688 for (i = 0; i < Nv / cdim; ++i) { 9689 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9690 for (d = 0; d < cdim; ++d) { 9691 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9692 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9693 } 9694 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9695 } 9696 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9697 for (cl = 0; cl < clSize * 2; cl += 2) { 9698 const PetscInt edge = closure[cl]; 9699 9700 if ((edge >= eStart) && (edge < eEnd)) { 9701 PetscReal len; 9702 9703 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9704 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9705 } 9706 } 9707 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9708 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9709 } 9710 } 9711 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9712 9713 if (size > 1) { 9714 PetscMPIInt blockLengths[2] = {4, 1}; 9715 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9716 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9717 MPI_Op statReduce; 9718 9719 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9720 PetscCallMPI(MPI_Type_commit(&statType)); 9721 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9722 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9723 PetscCallMPI(MPI_Op_free(&statReduce)); 9724 PetscCallMPI(MPI_Type_free(&statType)); 9725 } else { 9726 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9727 } 9728 if (rank == 0) { 9729 count = globalStats.count; 9730 min = globalStats.min; 9731 max = globalStats.max; 9732 mean = globalStats.sum / globalStats.count; 9733 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9734 } 9735 9736 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)); 9737 PetscCall(PetscFree2(J, invJ)); 9738 9739 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9740 if (dmCoarse) { 9741 PetscBool isplex; 9742 9743 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9744 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9745 } 9746 PetscFunctionReturn(PETSC_SUCCESS); 9747 } 9748 9749 /*@ 9750 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9751 orthogonal quality below given tolerance. 9752 9753 Collective 9754 9755 Input Parameters: 9756 + dm - The `DMPLEX` object 9757 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9758 - atol - [0, 1] Absolute tolerance for tagging cells. 9759 9760 Output Parameters: 9761 + OrthQual - `Vec` containing orthogonal quality per cell 9762 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9763 9764 Options Database Keys: 9765 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9766 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9767 9768 Level: intermediate 9769 9770 Notes: 9771 Orthogonal quality is given by the following formula\: 9772 9773 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9774 9775 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 9776 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9777 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9778 calculating the cosine of the angle between these vectors. 9779 9780 Orthogonal quality ranges from 1 (best) to 0 (worst). 9781 9782 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9783 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9784 9785 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9786 9787 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9788 @*/ 9789 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9790 { 9791 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9792 PetscInt *idx; 9793 PetscScalar *oqVals; 9794 const PetscScalar *cellGeomArr, *faceGeomArr; 9795 PetscReal *ci, *fi, *Ai; 9796 MPI_Comm comm; 9797 Vec cellgeom, facegeom; 9798 DM dmFace, dmCell; 9799 IS glob; 9800 ISLocalToGlobalMapping ltog; 9801 PetscViewer vwr; 9802 9803 PetscFunctionBegin; 9804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9805 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9806 PetscAssertPointer(OrthQual, 4); 9807 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9808 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9809 PetscCall(DMGetDimension(dm, &nc)); 9810 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9811 { 9812 DMPlexInterpolatedFlag interpFlag; 9813 9814 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9815 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9816 PetscMPIInt rank; 9817 9818 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9819 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9820 } 9821 } 9822 if (OrthQualLabel) { 9823 PetscAssertPointer(OrthQualLabel, 5); 9824 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9825 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9826 } else { 9827 *OrthQualLabel = NULL; 9828 } 9829 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9830 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9831 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9832 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9833 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9834 PetscCall(VecCreate(comm, OrthQual)); 9835 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9836 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9837 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9838 PetscCall(VecSetUp(*OrthQual)); 9839 PetscCall(ISDestroy(&glob)); 9840 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9841 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9842 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9843 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9844 PetscCall(VecGetDM(cellgeom, &dmCell)); 9845 PetscCall(VecGetDM(facegeom, &dmFace)); 9846 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9847 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9848 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9849 PetscInt cellarr[2], *adj = NULL; 9850 PetscScalar *cArr, *fArr; 9851 PetscReal minvalc = 1.0, minvalf = 1.0; 9852 PetscFVCellGeom *cg; 9853 9854 idx[cellIter] = cell - cStart; 9855 cellarr[0] = cell; 9856 /* Make indexing into cellGeom easier */ 9857 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9858 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9859 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9860 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9861 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9862 PetscInt i; 9863 const PetscInt neigh = adj[cellneigh]; 9864 PetscReal normci = 0, normfi = 0, normai = 0; 9865 PetscFVCellGeom *cgneigh; 9866 PetscFVFaceGeom *fg; 9867 9868 /* Don't count ourselves in the neighbor list */ 9869 if (neigh == cell) continue; 9870 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9871 cellarr[1] = neigh; 9872 { 9873 PetscInt numcovpts; 9874 const PetscInt *covpts; 9875 9876 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9877 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9878 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9879 } 9880 9881 /* Compute c_i, f_i and their norms */ 9882 for (i = 0; i < nc; i++) { 9883 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9884 fi[i] = fg->centroid[i] - cg->centroid[i]; 9885 Ai[i] = fg->normal[i]; 9886 normci += PetscPowReal(ci[i], 2); 9887 normfi += PetscPowReal(fi[i], 2); 9888 normai += PetscPowReal(Ai[i], 2); 9889 } 9890 normci = PetscSqrtReal(normci); 9891 normfi = PetscSqrtReal(normfi); 9892 normai = PetscSqrtReal(normai); 9893 9894 /* Normalize and compute for each face-cell-normal pair */ 9895 for (i = 0; i < nc; i++) { 9896 ci[i] = ci[i] / normci; 9897 fi[i] = fi[i] / normfi; 9898 Ai[i] = Ai[i] / normai; 9899 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9900 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9901 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9902 } 9903 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9904 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9905 } 9906 PetscCall(PetscFree(adj)); 9907 PetscCall(PetscFree2(cArr, fArr)); 9908 /* Defer to cell if they're equal */ 9909 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9910 if (OrthQualLabel) { 9911 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9912 } 9913 } 9914 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9915 PetscCall(VecAssemblyBegin(*OrthQual)); 9916 PetscCall(VecAssemblyEnd(*OrthQual)); 9917 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9918 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9919 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9920 if (OrthQualLabel) { 9921 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9922 } 9923 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9924 PetscCall(PetscViewerDestroy(&vwr)); 9925 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9926 PetscFunctionReturn(PETSC_SUCCESS); 9927 } 9928 9929 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9930 * interpolator construction */ 9931 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9932 { 9933 PetscSection section, newSection, gsection; 9934 PetscSF sf; 9935 PetscBool hasConstraints, ghasConstraints; 9936 9937 PetscFunctionBegin; 9938 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9939 PetscAssertPointer(odm, 2); 9940 PetscCall(DMGetLocalSection(dm, §ion)); 9941 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9942 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9943 if (!ghasConstraints) { 9944 PetscCall(PetscObjectReference((PetscObject)dm)); 9945 *odm = dm; 9946 PetscFunctionReturn(PETSC_SUCCESS); 9947 } 9948 PetscCall(DMClone(dm, odm)); 9949 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 9950 PetscCall(DMGetLocalSection(*odm, &newSection)); 9951 PetscCall(DMGetPointSF(*odm, &sf)); 9952 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9953 PetscCall(DMSetGlobalSection(*odm, gsection)); 9954 PetscCall(PetscSectionDestroy(&gsection)); 9955 PetscFunctionReturn(PETSC_SUCCESS); 9956 } 9957 9958 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9959 { 9960 DM dmco, dmfo; 9961 Mat interpo; 9962 Vec rscale; 9963 Vec cglobalo, clocal; 9964 Vec fglobal, fglobalo, flocal; 9965 PetscBool regular; 9966 9967 PetscFunctionBegin; 9968 PetscCall(DMGetFullDM(dmc, &dmco)); 9969 PetscCall(DMGetFullDM(dmf, &dmfo)); 9970 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9971 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9972 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9973 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9974 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9975 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9976 PetscCall(VecSet(cglobalo, 0.)); 9977 PetscCall(VecSet(clocal, 0.)); 9978 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9979 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9980 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9981 PetscCall(VecSet(fglobal, 0.)); 9982 PetscCall(VecSet(fglobalo, 0.)); 9983 PetscCall(VecSet(flocal, 0.)); 9984 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9985 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9986 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9987 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9988 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9989 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9990 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9991 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9992 *shift = fglobal; 9993 PetscCall(VecDestroy(&flocal)); 9994 PetscCall(VecDestroy(&fglobalo)); 9995 PetscCall(VecDestroy(&clocal)); 9996 PetscCall(VecDestroy(&cglobalo)); 9997 PetscCall(VecDestroy(&rscale)); 9998 PetscCall(MatDestroy(&interpo)); 9999 PetscCall(DMDestroy(&dmfo)); 10000 PetscCall(DMDestroy(&dmco)); 10001 PetscFunctionReturn(PETSC_SUCCESS); 10002 } 10003 10004 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10005 { 10006 PetscObject shifto; 10007 Vec shift; 10008 10009 PetscFunctionBegin; 10010 if (!interp) { 10011 Vec rscale; 10012 10013 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10014 PetscCall(VecDestroy(&rscale)); 10015 } else { 10016 PetscCall(PetscObjectReference((PetscObject)interp)); 10017 } 10018 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10019 if (!shifto) { 10020 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10021 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10022 shifto = (PetscObject)shift; 10023 PetscCall(VecDestroy(&shift)); 10024 } 10025 shift = (Vec)shifto; 10026 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10027 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10028 PetscCall(MatDestroy(&interp)); 10029 PetscFunctionReturn(PETSC_SUCCESS); 10030 } 10031 10032 /* Pointwise interpolation 10033 Just code FEM for now 10034 u^f = I u^c 10035 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10036 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10037 I_{ij} = psi^f_i phi^c_j 10038 */ 10039 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10040 { 10041 PetscSection gsc, gsf; 10042 PetscInt m, n; 10043 void *ctx; 10044 DM cdm; 10045 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10046 10047 PetscFunctionBegin; 10048 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10049 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10050 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10051 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10052 10053 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10054 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10055 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10056 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10057 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10058 10059 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10060 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10061 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10062 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10063 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10064 if (scaling) { 10065 /* Use naive scaling */ 10066 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10067 } 10068 PetscFunctionReturn(PETSC_SUCCESS); 10069 } 10070 10071 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10072 { 10073 VecScatter ctx; 10074 10075 PetscFunctionBegin; 10076 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10077 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10078 PetscCall(VecScatterDestroy(&ctx)); 10079 PetscFunctionReturn(PETSC_SUCCESS); 10080 } 10081 10082 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[]) 10083 { 10084 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10085 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10086 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10087 } 10088 10089 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10090 { 10091 DM dmc; 10092 PetscDS ds; 10093 Vec ones, locmass; 10094 IS cellIS; 10095 PetscFormKey key; 10096 PetscInt depth; 10097 10098 PetscFunctionBegin; 10099 PetscCall(DMClone(dm, &dmc)); 10100 PetscCall(DMCopyDisc(dm, dmc)); 10101 PetscCall(DMGetDS(dmc, &ds)); 10102 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10103 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10104 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10105 else PetscCall(DMGetLocalVector(dm, &locmass)); 10106 PetscCall(DMGetLocalVector(dm, &ones)); 10107 PetscCall(DMPlexGetDepth(dm, &depth)); 10108 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10109 PetscCall(VecSet(locmass, 0.0)); 10110 PetscCall(VecSet(ones, 1.0)); 10111 key.label = NULL; 10112 key.value = 0; 10113 key.field = 0; 10114 key.part = 0; 10115 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10116 PetscCall(ISDestroy(&cellIS)); 10117 if (mass) { 10118 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10119 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10120 } 10121 PetscCall(DMRestoreLocalVector(dm, &ones)); 10122 if (lmass) *lmass = locmass; 10123 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10124 PetscCall(DMDestroy(&dmc)); 10125 PetscFunctionReturn(PETSC_SUCCESS); 10126 } 10127 10128 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10129 { 10130 PetscSection gsc, gsf; 10131 PetscInt m, n; 10132 void *ctx; 10133 DM cdm; 10134 PetscBool regular; 10135 10136 PetscFunctionBegin; 10137 if (dmFine == dmCoarse) { 10138 DM dmc; 10139 PetscDS ds; 10140 PetscWeakForm wf; 10141 Vec u; 10142 IS cellIS; 10143 PetscFormKey key; 10144 PetscInt depth; 10145 10146 PetscCall(DMClone(dmFine, &dmc)); 10147 PetscCall(DMCopyDisc(dmFine, dmc)); 10148 PetscCall(DMGetDS(dmc, &ds)); 10149 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10150 PetscCall(PetscWeakFormClear(wf)); 10151 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10152 PetscCall(DMCreateMatrix(dmc, mass)); 10153 PetscCall(DMGetLocalVector(dmc, &u)); 10154 PetscCall(DMPlexGetDepth(dmc, &depth)); 10155 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10156 PetscCall(MatZeroEntries(*mass)); 10157 key.label = NULL; 10158 key.value = 0; 10159 key.field = 0; 10160 key.part = 0; 10161 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10162 PetscCall(ISDestroy(&cellIS)); 10163 PetscCall(DMRestoreLocalVector(dmc, &u)); 10164 PetscCall(DMDestroy(&dmc)); 10165 } else { 10166 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10167 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10168 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10169 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10170 10171 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10172 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10173 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10174 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10175 10176 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10177 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10178 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10179 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10180 } 10181 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10182 PetscFunctionReturn(PETSC_SUCCESS); 10183 } 10184 10185 /*@ 10186 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10187 10188 Input Parameter: 10189 . dm - The `DMPLEX` object 10190 10191 Output Parameter: 10192 . regular - The flag 10193 10194 Level: intermediate 10195 10196 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10197 @*/ 10198 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10199 { 10200 PetscFunctionBegin; 10201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10202 PetscAssertPointer(regular, 2); 10203 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10204 PetscFunctionReturn(PETSC_SUCCESS); 10205 } 10206 10207 /*@ 10208 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10209 10210 Input Parameters: 10211 + dm - The `DMPLEX` object 10212 - regular - The flag 10213 10214 Level: intermediate 10215 10216 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10217 @*/ 10218 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10219 { 10220 PetscFunctionBegin; 10221 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10222 ((DM_Plex *)dm->data)->regularRefinement = regular; 10223 PetscFunctionReturn(PETSC_SUCCESS); 10224 } 10225 10226 /*@ 10227 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10228 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10229 10230 Not Collective 10231 10232 Input Parameter: 10233 . dm - The `DMPLEX` object 10234 10235 Output Parameters: 10236 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10237 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10238 10239 Level: intermediate 10240 10241 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10242 @*/ 10243 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10244 { 10245 DM_Plex *plex = (DM_Plex *)dm->data; 10246 10247 PetscFunctionBegin; 10248 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10249 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10250 if (anchorSection) *anchorSection = plex->anchorSection; 10251 if (anchorIS) *anchorIS = plex->anchorIS; 10252 PetscFunctionReturn(PETSC_SUCCESS); 10253 } 10254 10255 /*@ 10256 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10257 10258 Collective 10259 10260 Input Parameters: 10261 + dm - The `DMPLEX` object 10262 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10263 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10264 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10265 10266 Level: intermediate 10267 10268 Notes: 10269 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10270 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10271 combination of other points' degrees of freedom. 10272 10273 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10274 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10275 10276 The reference counts of `anchorSection` and `anchorIS` are incremented. 10277 10278 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10279 @*/ 10280 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10281 { 10282 DM_Plex *plex = (DM_Plex *)dm->data; 10283 PetscMPIInt result; 10284 10285 PetscFunctionBegin; 10286 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10287 if (anchorSection) { 10288 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10289 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10290 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10291 } 10292 if (anchorIS) { 10293 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10294 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10295 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10296 } 10297 10298 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10299 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10300 plex->anchorSection = anchorSection; 10301 10302 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10303 PetscCall(ISDestroy(&plex->anchorIS)); 10304 plex->anchorIS = anchorIS; 10305 10306 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10307 PetscInt size, a, pStart, pEnd; 10308 const PetscInt *anchors; 10309 10310 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10311 PetscCall(ISGetLocalSize(anchorIS, &size)); 10312 PetscCall(ISGetIndices(anchorIS, &anchors)); 10313 for (a = 0; a < size; a++) { 10314 PetscInt p; 10315 10316 p = anchors[a]; 10317 if (p >= pStart && p < pEnd) { 10318 PetscInt dof; 10319 10320 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10321 if (dof) { 10322 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10323 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10324 } 10325 } 10326 } 10327 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10328 } 10329 /* reset the generic constraints */ 10330 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10331 PetscFunctionReturn(PETSC_SUCCESS); 10332 } 10333 10334 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10335 { 10336 PetscSection anchorSection; 10337 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10338 10339 PetscFunctionBegin; 10340 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10341 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10342 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10343 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10344 if (numFields) { 10345 PetscInt f; 10346 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10347 10348 for (f = 0; f < numFields; f++) { 10349 PetscInt numComp; 10350 10351 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10352 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10353 } 10354 } 10355 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10356 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10357 pStart = PetscMax(pStart, sStart); 10358 pEnd = PetscMin(pEnd, sEnd); 10359 pEnd = PetscMax(pStart, pEnd); 10360 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10361 for (p = pStart; p < pEnd; p++) { 10362 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10363 if (dof) { 10364 PetscCall(PetscSectionGetDof(section, p, &dof)); 10365 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10366 for (f = 0; f < numFields; f++) { 10367 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10368 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10369 } 10370 } 10371 } 10372 PetscCall(PetscSectionSetUp(*cSec)); 10373 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10374 PetscFunctionReturn(PETSC_SUCCESS); 10375 } 10376 10377 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10378 { 10379 PetscSection aSec; 10380 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10381 const PetscInt *anchors; 10382 PetscInt numFields, f; 10383 IS aIS; 10384 MatType mtype; 10385 PetscBool iscuda, iskokkos; 10386 10387 PetscFunctionBegin; 10388 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10389 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10390 PetscCall(PetscSectionGetStorageSize(section, &n)); 10391 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10392 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10393 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10394 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10395 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10396 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10397 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10398 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10399 else mtype = MATSEQAIJ; 10400 PetscCall(MatSetType(*cMat, mtype)); 10401 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10402 PetscCall(ISGetIndices(aIS, &anchors)); 10403 /* cSec will be a subset of aSec and section */ 10404 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10405 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10406 PetscCall(PetscMalloc1(m + 1, &i)); 10407 i[0] = 0; 10408 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10409 for (p = pStart; p < pEnd; p++) { 10410 PetscInt rDof, rOff, r; 10411 10412 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10413 if (!rDof) continue; 10414 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10415 if (numFields) { 10416 for (f = 0; f < numFields; f++) { 10417 annz = 0; 10418 for (r = 0; r < rDof; r++) { 10419 a = anchors[rOff + r]; 10420 if (a < sStart || a >= sEnd) continue; 10421 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10422 annz += aDof; 10423 } 10424 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10425 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10426 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10427 } 10428 } else { 10429 annz = 0; 10430 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10431 for (q = 0; q < dof; q++) { 10432 a = anchors[rOff + q]; 10433 if (a < sStart || a >= sEnd) continue; 10434 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10435 annz += aDof; 10436 } 10437 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10438 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10439 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10440 } 10441 } 10442 nnz = i[m]; 10443 PetscCall(PetscMalloc1(nnz, &j)); 10444 offset = 0; 10445 for (p = pStart; p < pEnd; p++) { 10446 if (numFields) { 10447 for (f = 0; f < numFields; f++) { 10448 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10449 for (q = 0; q < dof; q++) { 10450 PetscInt rDof, rOff, r; 10451 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10452 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10453 for (r = 0; r < rDof; r++) { 10454 PetscInt s; 10455 10456 a = anchors[rOff + r]; 10457 if (a < sStart || a >= sEnd) continue; 10458 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10459 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10460 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10461 } 10462 } 10463 } 10464 } else { 10465 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10466 for (q = 0; q < dof; q++) { 10467 PetscInt rDof, rOff, r; 10468 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10469 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10470 for (r = 0; r < rDof; r++) { 10471 PetscInt s; 10472 10473 a = anchors[rOff + r]; 10474 if (a < sStart || a >= sEnd) continue; 10475 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10476 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10477 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10478 } 10479 } 10480 } 10481 } 10482 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10483 PetscCall(PetscFree(i)); 10484 PetscCall(PetscFree(j)); 10485 PetscCall(ISRestoreIndices(aIS, &anchors)); 10486 PetscFunctionReturn(PETSC_SUCCESS); 10487 } 10488 10489 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10490 { 10491 DM_Plex *plex = (DM_Plex *)dm->data; 10492 PetscSection anchorSection, section, cSec; 10493 Mat cMat; 10494 10495 PetscFunctionBegin; 10496 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10497 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10498 if (anchorSection) { 10499 PetscInt Nf; 10500 10501 PetscCall(DMGetLocalSection(dm, §ion)); 10502 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10503 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10504 PetscCall(DMGetNumFields(dm, &Nf)); 10505 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10506 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10507 PetscCall(PetscSectionDestroy(&cSec)); 10508 PetscCall(MatDestroy(&cMat)); 10509 } 10510 PetscFunctionReturn(PETSC_SUCCESS); 10511 } 10512 10513 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10514 { 10515 IS subis; 10516 PetscSection section, subsection; 10517 10518 PetscFunctionBegin; 10519 PetscCall(DMGetLocalSection(dm, §ion)); 10520 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10521 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10522 /* Create subdomain */ 10523 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10524 /* Create submodel */ 10525 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10526 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10527 PetscCall(DMSetLocalSection(*subdm, subsection)); 10528 PetscCall(PetscSectionDestroy(&subsection)); 10529 PetscCall(DMCopyDisc(dm, *subdm)); 10530 /* Create map from submodel to global model */ 10531 if (is) { 10532 PetscSection sectionGlobal, subsectionGlobal; 10533 IS spIS; 10534 const PetscInt *spmap; 10535 PetscInt *subIndices; 10536 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10537 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10538 10539 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10540 PetscCall(ISGetIndices(spIS, &spmap)); 10541 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10542 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10543 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10544 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10545 for (p = pStart; p < pEnd; ++p) { 10546 PetscInt gdof, pSubSize = 0; 10547 10548 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10549 if (gdof > 0) { 10550 for (f = 0; f < Nf; ++f) { 10551 PetscInt fdof, fcdof; 10552 10553 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10554 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10555 pSubSize += fdof - fcdof; 10556 } 10557 subSize += pSubSize; 10558 if (pSubSize) { 10559 if (bs < 0) { 10560 bs = pSubSize; 10561 } else if (bs != pSubSize) { 10562 /* Layout does not admit a pointwise block size */ 10563 bs = 1; 10564 } 10565 } 10566 } 10567 } 10568 /* Must have same blocksize on all procs (some might have no points) */ 10569 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10570 bsLocal[1] = bs; 10571 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10572 if (bsMinMax[0] != bsMinMax[1]) { 10573 bs = 1; 10574 } else { 10575 bs = bsMinMax[0]; 10576 } 10577 PetscCall(PetscMalloc1(subSize, &subIndices)); 10578 for (p = pStart; p < pEnd; ++p) { 10579 PetscInt gdof, goff; 10580 10581 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10582 if (gdof > 0) { 10583 const PetscInt point = spmap[p]; 10584 10585 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10586 for (f = 0; f < Nf; ++f) { 10587 PetscInt fdof, fcdof, fc, f2, poff = 0; 10588 10589 /* Can get rid of this loop by storing field information in the global section */ 10590 for (f2 = 0; f2 < f; ++f2) { 10591 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10592 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10593 poff += fdof - fcdof; 10594 } 10595 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10596 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10597 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10598 } 10599 } 10600 } 10601 PetscCall(ISRestoreIndices(spIS, &spmap)); 10602 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10603 if (bs > 1) { 10604 /* We need to check that the block size does not come from non-contiguous fields */ 10605 PetscInt i, j, set = 1; 10606 for (i = 0; i < subSize; i += bs) { 10607 for (j = 0; j < bs; ++j) { 10608 if (subIndices[i + j] != subIndices[i] + j) { 10609 set = 0; 10610 break; 10611 } 10612 } 10613 } 10614 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10615 } 10616 /* Attach nullspace */ 10617 for (f = 0; f < Nf; ++f) { 10618 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10619 if ((*subdm)->nullspaceConstructors[f]) break; 10620 } 10621 if (f < Nf) { 10622 MatNullSpace nullSpace; 10623 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10624 10625 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10626 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10627 } 10628 } 10629 PetscFunctionReturn(PETSC_SUCCESS); 10630 } 10631 10632 /*@ 10633 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10634 10635 Input Parameters: 10636 + dm - The `DM` 10637 - dummy - unused argument 10638 10639 Options Database Key: 10640 . -dm_plex_monitor_throughput - Activate the monitor 10641 10642 Level: developer 10643 10644 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10645 @*/ 10646 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10647 { 10648 PetscLogHandler default_handler; 10649 10650 PetscFunctionBegin; 10651 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10652 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10653 if (default_handler) { 10654 PetscLogEvent event; 10655 PetscEventPerfInfo eventInfo; 10656 PetscReal cellRate, flopRate; 10657 PetscInt cStart, cEnd, Nf, N; 10658 const char *name; 10659 10660 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10661 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10662 PetscCall(DMGetNumFields(dm, &Nf)); 10663 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10664 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10665 N = (cEnd - cStart) * Nf * eventInfo.count; 10666 flopRate = eventInfo.flops / eventInfo.time; 10667 cellRate = N / eventInfo.time; 10668 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))); 10669 } else { 10670 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."); 10671 } 10672 PetscFunctionReturn(PETSC_SUCCESS); 10673 } 10674