1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal" cells 74 75 Level: developer 76 77 Note: 78 This function requires that tensor cells are ordered last. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMLabel ctLabel; 85 IS valueIS; 86 const PetscInt *ctypes; 87 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 88 89 PetscFunctionBegin; 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 92 PetscCall(ISGetLocalSize(valueIS, &Nct)); 93 PetscCall(ISGetIndices(valueIS, &ctypes)); 94 if (!Nct) cS = cE = 0; 95 for (PetscInt t = 0; t < Nct; ++t) { 96 const PetscInt ct = ctypes[t]; 97 PetscInt ctS, ctE, ht; 98 99 if (ct == DM_POLYTOPE_UNKNOWN) { 100 // If any cells are not typed, just use all cells 101 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 102 break; 103 } 104 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_POINT_PRISM_TENSOR || ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) continue; 105 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 106 if (ctS >= ctE) continue; 107 // Check that a point has the right height 108 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 109 if (ht != height) continue; 110 cS = PetscMin(cS, ctS); 111 cE = PetscMax(cE, ctE); 112 } 113 PetscCall(ISDestroy(&valueIS)); 114 // Reset label for fast lookup 115 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 124 PetscInt *sStart, *sEnd; 125 PetscViewerVTKFieldType *ft; 126 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 127 DMLabel depthLabel, ctLabel; 128 129 PetscFunctionBegin; 130 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 162 } 163 164 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 165 *types = 0; 166 167 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 168 if (globalvcdof[c]) ++(*types); 169 } 170 171 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 172 t = 0; 173 if (globalvcdof[DM_NUM_POLYTOPES]) { 174 sStart[t] = vStart; 175 sEnd[t] = vEnd; 176 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 177 ++t; 178 } 179 180 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 181 if (globalvcdof[c]) { 182 const DMPolytopeType ict = (DMPolytopeType)c; 183 184 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 185 sStart[t] = cStart; 186 sEnd[t] = cEnd; 187 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 188 ++t; 189 } 190 } 191 192 if (!(*types)) { 193 if (field >= 0) { 194 const char *fieldname; 195 196 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 197 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 198 } else { 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 200 } 201 } 202 203 *ssStart = sStart; 204 *ssEnd = sEnd; 205 *sft = ft; 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 210 { 211 PetscFunctionBegin; 212 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 213 PetscFunctionReturn(PETSC_SUCCESS); 214 } 215 216 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 217 { 218 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 219 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 220 221 PetscFunctionBegin; 222 *ft = PETSC_VTK_INVALID; 223 PetscCall(DMGetCoordinateDim(dm, &cdim)); 224 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 225 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 226 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 227 if (field >= 0) { 228 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 229 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 230 } else { 231 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 232 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 233 } 234 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 235 if (globalvcdof[0]) { 236 *sStart = vStart; 237 *sEnd = vEnd; 238 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 239 else *ft = PETSC_VTK_POINT_FIELD; 240 } else if (globalvcdof[1]) { 241 *sStart = cStart; 242 *sEnd = cEnd; 243 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 244 else *ft = PETSC_VTK_CELL_FIELD; 245 } else { 246 if (field >= 0) { 247 const char *fieldname; 248 249 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 250 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 251 } else { 252 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 253 } 254 } 255 PetscFunctionReturn(PETSC_SUCCESS); 256 } 257 258 /*@ 259 DMPlexVecView1D - Plot many 1D solutions on the same line graph 260 261 Collective 262 263 Input Parameters: 264 + dm - The `DMPLEX` object 265 . n - The number of vectors 266 . u - The array of local vectors 267 - viewer - The `PetscViewer` 268 269 Level: advanced 270 271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 272 @*/ 273 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 274 { 275 PetscDS ds; 276 PetscDraw draw = NULL; 277 PetscDrawLG lg; 278 Vec coordinates; 279 const PetscScalar *coords, **sol; 280 PetscReal *vals; 281 PetscInt *Nc; 282 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 283 char **names; 284 285 PetscFunctionBegin; 286 PetscCall(DMGetDS(dm, &ds)); 287 PetscCall(PetscDSGetNumFields(ds, &Nf)); 288 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 289 PetscCall(PetscDSGetComponents(ds, &Nc)); 290 291 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 292 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 293 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 294 295 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 296 for (i = 0, l = 0; i < n; ++i) { 297 const char *vname; 298 299 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 300 for (f = 0; f < Nf; ++f) { 301 PetscObject disc; 302 const char *fname; 303 char tmpname[PETSC_MAX_PATH_LEN]; 304 305 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 306 /* TODO Create names for components */ 307 for (c = 0; c < Nc[f]; ++c, ++l) { 308 PetscCall(PetscObjectGetName(disc, &fname)); 309 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 312 PetscCall(PetscStrallocpy(tmpname, &names[l])); 313 } 314 } 315 } 316 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 317 /* Just add P_1 support for now */ 318 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 319 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 320 PetscCall(VecGetArrayRead(coordinates, &coords)); 321 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 322 for (v = vStart; v < vEnd; ++v) { 323 PetscScalar *x, *svals; 324 325 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 326 for (i = 0; i < n; ++i) { 327 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 328 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 329 } 330 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 331 } 332 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 333 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 334 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 335 PetscCall(PetscFree3(sol, names, vals)); 336 337 PetscCall(PetscDrawLGDraw(lg)); 338 PetscCall(PetscDrawLGDestroy(&lg)); 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 343 { 344 DM dm; 345 346 PetscFunctionBegin; 347 PetscCall(VecGetDM(u, &dm)); 348 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 349 PetscFunctionReturn(PETSC_SUCCESS); 350 } 351 352 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 353 { 354 DM dm; 355 PetscSection s; 356 PetscDraw draw, popup; 357 DM cdm; 358 PetscSection coordSection; 359 Vec coordinates; 360 const PetscScalar *array; 361 PetscReal lbound[3], ubound[3]; 362 PetscReal vbound[2], time; 363 PetscBool flg; 364 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 365 const char *name; 366 char title[PETSC_MAX_PATH_LEN]; 367 368 PetscFunctionBegin; 369 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 370 PetscCall(VecGetDM(v, &dm)); 371 PetscCall(DMGetCoordinateDim(dm, &dim)); 372 PetscCall(DMGetLocalSection(dm, &s)); 373 PetscCall(PetscSectionGetNumFields(s, &Nf)); 374 PetscCall(DMGetCoarsenLevel(dm, &level)); 375 PetscCall(DMGetCoordinateDM(dm, &cdm)); 376 PetscCall(DMGetLocalSection(cdm, &coordSection)); 377 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 378 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 379 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 380 381 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 382 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 383 384 PetscCall(VecGetLocalSize(coordinates, &N)); 385 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 386 PetscCall(PetscDrawClear(draw)); 387 388 /* Could implement something like DMDASelectFields() */ 389 for (f = 0; f < Nf; ++f) { 390 DM fdm = dm; 391 Vec fv = v; 392 IS fis; 393 char prefix[PETSC_MAX_PATH_LEN]; 394 const char *fname; 395 396 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 397 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 398 399 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 400 else prefix[0] = '\0'; 401 if (Nf > 1) { 402 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 403 PetscCall(VecGetSubVector(v, fis, &fv)); 404 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 405 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 406 } 407 for (comp = 0; comp < Nc; ++comp, ++w) { 408 PetscInt nmax = 2; 409 410 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 411 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 412 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 413 PetscCall(PetscDrawSetTitle(draw, title)); 414 415 /* TODO Get max and min only for this component */ 416 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 417 if (!flg) { 418 PetscCall(VecMin(fv, NULL, &vbound[0])); 419 PetscCall(VecMax(fv, NULL, &vbound[1])); 420 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 421 } 422 423 PetscCall(PetscDrawGetPopup(draw, &popup)); 424 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 425 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 426 PetscCall(VecGetArrayRead(fv, &array)); 427 for (c = cStart; c < cEnd; ++c) { 428 PetscScalar *coords = NULL, *a = NULL; 429 const PetscScalar *coords_arr; 430 PetscBool isDG; 431 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 432 433 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 434 if (a) { 435 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 436 color[1] = color[2] = color[3] = color[0]; 437 } else { 438 PetscScalar *vals = NULL; 439 PetscInt numVals, va; 440 441 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 442 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); 443 switch (numVals / Nc) { 444 case 3: /* P1 Triangle */ 445 case 4: /* P1 Quadrangle */ 446 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 447 break; 448 case 6: /* P2 Triangle */ 449 case 8: /* P2 Quadrangle */ 450 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 451 break; 452 default: 453 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 454 } 455 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 456 } 457 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 458 switch (numCoords) { 459 case 6: 460 case 12: /* Localized triangle */ 461 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])); 462 break; 463 case 8: 464 case 16: /* Localized quadrilateral */ 465 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])); 466 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])); 467 break; 468 default: 469 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 470 } 471 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 472 } 473 PetscCall(VecRestoreArrayRead(fv, &array)); 474 PetscCall(PetscDrawFlush(draw)); 475 PetscCall(PetscDrawPause(draw)); 476 PetscCall(PetscDrawSave(draw)); 477 } 478 if (Nf > 1) { 479 PetscCall(VecRestoreSubVector(v, fis, &fv)); 480 PetscCall(ISDestroy(&fis)); 481 PetscCall(DMDestroy(&fdm)); 482 } 483 } 484 PetscFunctionReturn(PETSC_SUCCESS); 485 } 486 487 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 488 { 489 DM dm; 490 PetscDraw draw; 491 PetscInt dim; 492 PetscBool isnull; 493 494 PetscFunctionBegin; 495 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 496 PetscCall(PetscDrawIsNull(draw, &isnull)); 497 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 498 499 PetscCall(VecGetDM(v, &dm)); 500 PetscCall(DMGetCoordinateDim(dm, &dim)); 501 switch (dim) { 502 case 1: 503 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 504 break; 505 case 2: 506 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 507 break; 508 default: 509 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 510 } 511 PetscFunctionReturn(PETSC_SUCCESS); 512 } 513 514 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 515 { 516 DM dm; 517 Vec locv; 518 const char *name; 519 PetscSection section; 520 PetscInt pStart, pEnd; 521 PetscInt numFields; 522 PetscViewerVTKFieldType ft; 523 524 PetscFunctionBegin; 525 PetscCall(VecGetDM(v, &dm)); 526 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 527 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 528 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 529 PetscCall(VecCopy(v, locv)); 530 PetscCall(DMGetLocalSection(dm, §ion)); 531 PetscCall(PetscSectionGetNumFields(section, &numFields)); 532 if (!numFields) { 533 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 534 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 535 } else { 536 PetscInt f; 537 538 for (f = 0; f < numFields; f++) { 539 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 540 if (ft == PETSC_VTK_INVALID) continue; 541 PetscCall(PetscObjectReference((PetscObject)locv)); 542 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 543 } 544 PetscCall(VecDestroy(&locv)); 545 } 546 PetscFunctionReturn(PETSC_SUCCESS); 547 } 548 549 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 550 { 551 DM dm; 552 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 553 554 PetscFunctionBegin; 555 PetscCall(VecGetDM(v, &dm)); 556 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 562 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 563 PetscInt i, numFields; 564 PetscObject fe; 565 PetscBool fem = PETSC_FALSE; 566 Vec locv = v; 567 const char *name; 568 PetscInt step; 569 PetscReal time; 570 571 PetscCall(DMGetNumFields(dm, &numFields)); 572 for (i = 0; i < numFields; i++) { 573 PetscCall(DMGetField(dm, i, NULL, &fe)); 574 if (fe->classid == PETSCFE_CLASSID) { 575 fem = PETSC_TRUE; 576 break; 577 } 578 } 579 if (fem) { 580 PetscObject isZero; 581 582 PetscCall(DMGetLocalVector(dm, &locv)); 583 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 584 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 585 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 586 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 587 PetscCall(VecCopy(v, locv)); 588 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 589 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 590 } 591 if (isvtk) { 592 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 593 } else if (ishdf5) { 594 #if defined(PETSC_HAVE_HDF5) 595 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 596 #else 597 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 598 #endif 599 } else if (isdraw) { 600 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 601 } else if (isglvis) { 602 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 603 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 604 PetscCall(VecView_GLVis(locv, viewer)); 605 } else if (iscgns) { 606 #if defined(PETSC_HAVE_CGNS) 607 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 608 #else 609 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 610 #endif 611 } 612 if (fem) { 613 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 614 PetscCall(DMRestoreLocalVector(dm, &locv)); 615 } 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 PetscFunctionReturn(PETSC_SUCCESS); 624 } 625 626 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 627 { 628 DM dm; 629 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 630 631 PetscFunctionBegin; 632 PetscCall(VecGetDM(v, &dm)); 633 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (isvtk || isdraw || isglvis || iscgns) { 641 Vec locv; 642 PetscObject isZero; 643 const char *name; 644 645 PetscCall(DMGetLocalVector(dm, &locv)); 646 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 647 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 648 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 649 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 650 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 651 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 652 PetscCall(VecView_Plex_Local(locv, viewer)); 653 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 654 PetscCall(DMRestoreLocalVector(dm, &locv)); 655 } else if (ishdf5) { 656 #if defined(PETSC_HAVE_HDF5) 657 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 658 #else 659 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 660 #endif 661 } else if (isexodusii) { 662 #if defined(PETSC_HAVE_EXODUSII) 663 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 664 #else 665 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 666 #endif 667 } else { 668 PetscBool isseq; 669 670 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 671 if (isseq) PetscCall(VecView_Seq(v, viewer)); 672 else PetscCall(VecView_MPI(v, viewer)); 673 } 674 PetscFunctionReturn(PETSC_SUCCESS); 675 } 676 677 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 678 { 679 DM dm; 680 MPI_Comm comm; 681 PetscViewerFormat format; 682 Vec v; 683 PetscBool isvtk, ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 688 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 689 PetscCall(PetscViewerGetFormat(viewer, &format)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 692 if (format == PETSC_VIEWER_NATIVE) { 693 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 694 /* this need a better fix */ 695 if (dm->useNatural) { 696 if (dm->sfNatural) { 697 const char *vecname; 698 PetscInt n, nroots; 699 700 PetscCall(VecGetLocalSize(originalv, &n)); 701 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 702 if (n == nroots) { 703 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 704 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 705 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 706 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 707 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 709 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 710 } else v = originalv; 711 } else v = originalv; 712 713 if (ishdf5) { 714 #if defined(PETSC_HAVE_HDF5) 715 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 716 #else 717 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 718 #endif 719 } else if (isvtk) { 720 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 721 } else { 722 PetscBool isseq; 723 724 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 725 if (isseq) PetscCall(VecView_Seq(v, viewer)); 726 else PetscCall(VecView_MPI(v, viewer)); 727 } 728 if (v != originalv) PetscCall(VecDestroy(&v)); 729 PetscFunctionReturn(PETSC_SUCCESS); 730 } 731 732 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 733 { 734 DM dm; 735 PetscBool ishdf5; 736 737 PetscFunctionBegin; 738 PetscCall(VecGetDM(v, &dm)); 739 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 740 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 741 if (ishdf5) { 742 DM dmBC; 743 Vec gv; 744 const char *name; 745 746 PetscCall(DMGetOutputDM(dm, &dmBC)); 747 PetscCall(DMGetGlobalVector(dmBC, &gv)); 748 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 749 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 750 PetscCall(VecLoad_Default(gv, viewer)); 751 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 753 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 754 } else PetscCall(VecLoad_Default(v, viewer)); 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 759 { 760 DM dm; 761 PetscBool ishdf5, isexodusii; 762 763 PetscFunctionBegin; 764 PetscCall(VecGetDM(v, &dm)); 765 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 768 if (ishdf5) { 769 #if defined(PETSC_HAVE_HDF5) 770 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 771 #else 772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 773 #endif 774 } else if (isexodusii) { 775 #if defined(PETSC_HAVE_EXODUSII) 776 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 777 #else 778 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 779 #endif 780 } else PetscCall(VecLoad_Default(v, viewer)); 781 PetscFunctionReturn(PETSC_SUCCESS); 782 } 783 784 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 785 { 786 DM dm; 787 PetscViewerFormat format; 788 PetscBool ishdf5; 789 790 PetscFunctionBegin; 791 PetscCall(VecGetDM(originalv, &dm)); 792 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 793 PetscCall(PetscViewerGetFormat(viewer, &format)); 794 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 795 if (format == PETSC_VIEWER_NATIVE) { 796 if (dm->useNatural) { 797 if (dm->sfNatural) { 798 if (ishdf5) { 799 #if defined(PETSC_HAVE_HDF5) 800 Vec v; 801 const char *vecname; 802 803 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 804 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 805 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 806 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 807 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 808 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 809 PetscCall(VecDestroy(&v)); 810 #else 811 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 812 #endif 813 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 814 } 815 } else PetscCall(VecLoad_Default(originalv, viewer)); 816 } 817 PetscFunctionReturn(PETSC_SUCCESS); 818 } 819 820 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 821 { 822 PetscSection coordSection; 823 Vec coordinates; 824 DMLabel depthLabel, celltypeLabel; 825 const char *name[4]; 826 const PetscScalar *a; 827 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 828 829 PetscFunctionBegin; 830 PetscCall(DMGetDimension(dm, &dim)); 831 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 832 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 833 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 834 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 835 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 836 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 837 PetscCall(VecGetArrayRead(coordinates, &a)); 838 name[0] = "vertex"; 839 name[1] = "edge"; 840 name[dim - 1] = "face"; 841 name[dim] = "cell"; 842 for (c = cStart; c < cEnd; ++c) { 843 PetscInt *closure = NULL; 844 PetscInt closureSize, cl, ct; 845 846 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 847 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 848 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 849 PetscCall(PetscViewerASCIIPushTab(viewer)); 850 for (cl = 0; cl < closureSize * 2; cl += 2) { 851 PetscInt point = closure[cl], depth, dof, off, d, p; 852 853 if ((point < pStart) || (point >= pEnd)) continue; 854 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 855 if (!dof) continue; 856 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 857 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 859 for (p = 0; p < dof / dim; ++p) { 860 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 861 for (d = 0; d < dim; ++d) { 862 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 863 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 864 } 865 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 866 } 867 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 868 } 869 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 870 PetscCall(PetscViewerASCIIPopTab(viewer)); 871 } 872 PetscCall(VecRestoreArrayRead(coordinates, &a)); 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875 876 typedef enum { 877 CS_CARTESIAN, 878 CS_POLAR, 879 CS_CYLINDRICAL, 880 CS_SPHERICAL 881 } CoordSystem; 882 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 883 884 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 885 { 886 PetscInt i; 887 888 PetscFunctionBegin; 889 if (dim > 3) { 890 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 891 } else { 892 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 893 894 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 895 switch (cs) { 896 case CS_CARTESIAN: 897 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 898 break; 899 case CS_POLAR: 900 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 901 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 902 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 903 break; 904 case CS_CYLINDRICAL: 905 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 906 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 907 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 908 trcoords[2] = coords[2]; 909 break; 910 case CS_SPHERICAL: 911 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 912 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 913 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 914 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 915 break; 916 } 917 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 918 } 919 PetscFunctionReturn(PETSC_SUCCESS); 920 } 921 922 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 923 { 924 DM_Plex *mesh = (DM_Plex *)dm->data; 925 DM cdm, cdmCell; 926 PetscSection coordSection, coordSectionCell; 927 Vec coordinates, coordinatesCell; 928 PetscViewerFormat format; 929 930 PetscFunctionBegin; 931 PetscCall(PetscViewerGetFormat(viewer, &format)); 932 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 933 const char *name; 934 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 935 PetscInt pStart, pEnd, p, numLabels, l; 936 PetscMPIInt rank, size; 937 938 PetscCall(DMGetCoordinateDM(dm, &cdm)); 939 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 940 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 941 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 942 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 943 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 944 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 945 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 946 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 947 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 949 PetscCall(DMGetDimension(dm, &dim)); 950 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 951 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 952 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 953 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 955 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 956 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 957 for (p = pStart; p < pEnd; ++p) { 958 PetscInt dof, off, s; 959 960 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 961 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 962 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 963 } 964 PetscCall(PetscViewerFlush(viewer)); 965 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 966 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 967 for (p = pStart; p < pEnd; ++p) { 968 PetscInt dof, off, c; 969 970 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 971 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 972 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])); 973 } 974 PetscCall(PetscViewerFlush(viewer)); 975 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 976 if (coordSection && coordinates) { 977 CoordSystem cs = CS_CARTESIAN; 978 const PetscScalar *array, *arrayCell = NULL; 979 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 980 PetscMPIInt rank; 981 const char *name; 982 983 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 984 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 985 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 986 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 987 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 988 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 989 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 990 pStart = PetscMin(pvStart, pcStart); 991 pEnd = PetscMax(pvEnd, pcEnd); 992 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 994 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 995 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 996 997 PetscCall(VecGetArrayRead(coordinates, &array)); 998 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 999 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1000 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1001 for (p = pStart; p < pEnd; ++p) { 1002 PetscInt dof, off; 1003 1004 if (p >= pvStart && p < pvEnd) { 1005 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1006 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1007 if (dof) { 1008 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1009 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1010 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1011 } 1012 } 1013 if (cdmCell && p >= pcStart && p < pcEnd) { 1014 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1015 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1016 if (dof) { 1017 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1018 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1019 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1020 } 1021 } 1022 } 1023 PetscCall(PetscViewerFlush(viewer)); 1024 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1025 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1026 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1027 } 1028 PetscCall(DMGetNumLabels(dm, &numLabels)); 1029 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1030 for (l = 0; l < numLabels; ++l) { 1031 DMLabel label; 1032 PetscBool isdepth; 1033 const char *name; 1034 1035 PetscCall(DMGetLabelName(dm, l, &name)); 1036 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1037 if (isdepth) continue; 1038 PetscCall(DMGetLabel(dm, name, &label)); 1039 PetscCall(DMLabelView(label, viewer)); 1040 } 1041 if (size > 1) { 1042 PetscSF sf; 1043 1044 PetscCall(DMGetPointSF(dm, &sf)); 1045 PetscCall(PetscSFView(sf, viewer)); 1046 } 1047 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1088 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1089 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1090 if (!useLabels) numLabels = 0; 1091 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1092 if (!useColors) { 1093 numColors = 3; 1094 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1095 } 1096 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1097 if (!useColors) { 1098 numLColors = 4; 1099 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1100 } 1101 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1102 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1103 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1104 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1105 if (depth < dim) plotEdges = PETSC_FALSE; 1106 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1107 1108 /* filter points with labelvalue != labeldefaultvalue */ 1109 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1110 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1112 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1113 if (lflg) { 1114 DMLabel lbl; 1115 1116 PetscCall(DMGetLabel(dm, lname, &lbl)); 1117 if (lbl) { 1118 PetscInt val, defval; 1119 1120 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1121 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1122 for (c = pStart; c < pEnd; c++) { 1123 PetscInt *closure = NULL; 1124 PetscInt closureSize; 1125 1126 PetscCall(DMLabelGetValue(lbl, c, &val)); 1127 if (val == defval) continue; 1128 1129 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1130 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1131 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1132 } 1133 } 1134 } 1135 1136 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1137 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1138 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1139 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1140 \\documentclass[tikz]{standalone}\n\n\ 1141 \\usepackage{pgflibraryshapes}\n\ 1142 \\usetikzlibrary{backgrounds}\n\ 1143 \\usetikzlibrary{arrows}\n\ 1144 \\begin{document}\n")); 1145 if (size > 1) { 1146 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1147 for (p = 0; p < size; ++p) { 1148 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1149 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1150 } 1151 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1152 } 1153 if (drawHasse) { 1154 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1155 1156 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1168 } 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1170 1171 /* Plot vertices */ 1172 PetscCall(VecGetArray(coordinates, &coords)); 1173 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1174 for (v = vStart; v < vEnd; ++v) { 1175 PetscInt off, dof, d; 1176 PetscBool isLabeled = PETSC_FALSE; 1177 1178 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1179 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1180 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1181 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1182 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1183 for (d = 0; d < dof; ++d) { 1184 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1185 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1186 } 1187 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1188 if (dim == 3) { 1189 PetscReal tmp = tcoords[1]; 1190 tcoords[1] = tcoords[2]; 1191 tcoords[2] = -tmp; 1192 } 1193 for (d = 0; d < dof; ++d) { 1194 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1195 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1196 } 1197 if (drawHasse) color = colors[0 % numColors]; 1198 else color = colors[rank % numColors]; 1199 for (l = 0; l < numLabels; ++l) { 1200 PetscInt val; 1201 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1202 if (val >= 0) { 1203 color = lcolors[l % numLColors]; 1204 isLabeled = PETSC_TRUE; 1205 break; 1206 } 1207 } 1208 if (drawNumbers[0]) { 1209 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1210 } else if (drawColors[0]) { 1211 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1212 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1213 } 1214 PetscCall(VecRestoreArray(coordinates, &coords)); 1215 PetscCall(PetscViewerFlush(viewer)); 1216 /* Plot edges */ 1217 if (plotEdges) { 1218 PetscCall(VecGetArray(coordinates, &coords)); 1219 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1220 for (e = eStart; e < eEnd; ++e) { 1221 const PetscInt *cone; 1222 PetscInt coneSize, offA, offB, dof, d; 1223 1224 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1225 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1226 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1227 PetscCall(DMPlexGetCone(dm, e, &cone)); 1228 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1229 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1231 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1232 for (d = 0; d < dof; ++d) { 1233 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1234 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1235 } 1236 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1237 if (dim == 3) { 1238 PetscReal tmp = tcoords[1]; 1239 tcoords[1] = tcoords[2]; 1240 tcoords[2] = -tmp; 1241 } 1242 for (d = 0; d < dof; ++d) { 1243 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1244 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1245 } 1246 if (drawHasse) color = colors[1 % numColors]; 1247 else color = colors[rank % numColors]; 1248 for (l = 0; l < numLabels; ++l) { 1249 PetscInt val; 1250 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1251 if (val >= 0) { 1252 color = lcolors[l % numLColors]; 1253 break; 1254 } 1255 } 1256 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1257 } 1258 PetscCall(VecRestoreArray(coordinates, &coords)); 1259 PetscCall(PetscViewerFlush(viewer)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1261 } 1262 /* Plot cells */ 1263 if (dim == 3 || !drawNumbers[1]) { 1264 for (e = eStart; e < eEnd; ++e) { 1265 const PetscInt *cone; 1266 1267 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1268 color = colors[rank % numColors]; 1269 for (l = 0; l < numLabels; ++l) { 1270 PetscInt val; 1271 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1272 if (val >= 0) { 1273 color = lcolors[l % numLColors]; 1274 break; 1275 } 1276 } 1277 PetscCall(DMPlexGetCone(dm, e, &cone)); 1278 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1279 } 1280 } else { 1281 DMPolytopeType ct; 1282 1283 /* Drawing a 2D polygon */ 1284 for (c = cStart; c < cEnd; ++c) { 1285 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1286 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1287 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1288 const PetscInt *cone; 1289 PetscInt coneSize, e; 1290 1291 PetscCall(DMPlexGetCone(dm, c, &cone)); 1292 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1293 for (e = 0; e < coneSize; ++e) { 1294 const PetscInt *econe; 1295 1296 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1297 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)); 1298 } 1299 } else { 1300 PetscInt *closure = NULL; 1301 PetscInt closureSize, Nv = 0, v; 1302 1303 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1304 for (p = 0; p < closureSize * 2; p += 2) { 1305 const PetscInt point = closure[p]; 1306 1307 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1308 } 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1310 for (v = 0; v <= Nv; ++v) { 1311 const PetscInt vertex = closure[v % Nv]; 1312 1313 if (v > 0) { 1314 if (plotEdges) { 1315 const PetscInt *edge; 1316 PetscInt endpoints[2], ne; 1317 1318 endpoints[0] = closure[v - 1]; 1319 endpoints[1] = vertex; 1320 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1321 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1322 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1323 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1324 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1325 } 1326 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1327 } 1328 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1329 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1330 } 1331 } 1332 } 1333 for (c = cStart; c < cEnd; ++c) { 1334 double ccoords[3] = {0.0, 0.0, 0.0}; 1335 PetscBool isLabeled = PETSC_FALSE; 1336 PetscScalar *cellCoords = NULL; 1337 const PetscScalar *array; 1338 PetscInt numCoords, cdim, d; 1339 PetscBool isDG; 1340 1341 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1342 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1343 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1344 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1345 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1346 for (p = 0; p < numCoords / cdim; ++p) { 1347 for (d = 0; d < cdim; ++d) { 1348 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1349 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1350 } 1351 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1352 if (cdim == 3) { 1353 PetscReal tmp = tcoords[1]; 1354 tcoords[1] = tcoords[2]; 1355 tcoords[2] = -tmp; 1356 } 1357 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1358 } 1359 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1360 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1361 for (d = 0; d < cdim; ++d) { 1362 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1363 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1364 } 1365 if (drawHasse) color = colors[depth % numColors]; 1366 else color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 isLabeled = PETSC_TRUE; 1373 break; 1374 } 1375 } 1376 if (drawNumbers[dim]) { 1377 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1378 } else if (drawColors[dim]) { 1379 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1380 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1381 } 1382 if (drawHasse) { 1383 color = colors[depth % numColors]; 1384 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1389 1390 color = colors[1 % numColors]; 1391 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1396 1397 color = colors[0 % numColors]; 1398 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1403 1404 for (p = pStart; p < pEnd; ++p) { 1405 const PetscInt *cone; 1406 PetscInt coneSize, cp; 1407 1408 PetscCall(DMPlexGetCone(dm, p, &cone)); 1409 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1410 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1411 } 1412 } 1413 PetscCall(PetscViewerFlush(viewer)); 1414 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1417 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1418 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1419 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1420 PetscCall(PetscFree3(names, colors, lcolors)); 1421 PetscCall(PetscBTDestroy(&wp)); 1422 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1423 Vec cown, acown; 1424 VecScatter sct; 1425 ISLocalToGlobalMapping g2l; 1426 IS gid, acis; 1427 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1428 MPI_Group ggroup, ngroup; 1429 PetscScalar *array, nid; 1430 const PetscInt *idxs; 1431 PetscInt *idxs2, *start, *adjacency, *work; 1432 PetscInt64 lm[3], gm[3]; 1433 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1434 PetscMPIInt d1, d2, rank; 1435 1436 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1437 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1438 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1439 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1440 #endif 1441 if (ncomm != MPI_COMM_NULL) { 1442 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1443 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1444 d1 = 0; 1445 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1446 nid = d2; 1447 PetscCallMPI(MPI_Group_free(&ggroup)); 1448 PetscCallMPI(MPI_Group_free(&ngroup)); 1449 PetscCallMPI(MPI_Comm_free(&ncomm)); 1450 } else nid = 0.0; 1451 1452 /* Get connectivity */ 1453 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1454 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1455 1456 /* filter overlapped local cells */ 1457 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1458 PetscCall(ISGetIndices(gid, &idxs)); 1459 PetscCall(ISGetLocalSize(gid, &cum)); 1460 PetscCall(PetscMalloc1(cum, &idxs2)); 1461 for (c = cStart, cum = 0; c < cEnd; c++) { 1462 if (idxs[c - cStart] < 0) continue; 1463 idxs2[cum++] = idxs[c - cStart]; 1464 } 1465 PetscCall(ISRestoreIndices(gid, &idxs)); 1466 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1467 PetscCall(ISDestroy(&gid)); 1468 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1469 1470 /* support for node-aware cell locality */ 1471 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1472 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1473 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1474 PetscCall(VecGetArray(cown, &array)); 1475 for (c = 0; c < numVertices; c++) array[c] = nid; 1476 PetscCall(VecRestoreArray(cown, &array)); 1477 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1478 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1479 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(ISDestroy(&acis)); 1481 PetscCall(VecScatterDestroy(&sct)); 1482 PetscCall(VecDestroy(&cown)); 1483 1484 /* compute edgeCut */ 1485 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1486 PetscCall(PetscMalloc1(cum, &work)); 1487 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1488 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1489 PetscCall(ISDestroy(&gid)); 1490 PetscCall(VecGetArray(acown, &array)); 1491 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1492 PetscInt totl; 1493 1494 totl = start[c + 1] - start[c]; 1495 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1496 for (i = 0; i < totl; i++) { 1497 if (work[i] < 0) { 1498 ect += 1; 1499 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1500 } 1501 } 1502 } 1503 PetscCall(PetscFree(work)); 1504 PetscCall(VecRestoreArray(acown, &array)); 1505 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1506 lm[1] = -numVertices; 1507 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1509 lm[0] = ect; /* edgeCut */ 1510 lm[1] = ectn; /* node-aware edgeCut */ 1511 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1512 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1513 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1514 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1515 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1516 #else 1517 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1518 #endif 1519 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1520 PetscCall(PetscFree(start)); 1521 PetscCall(PetscFree(adjacency)); 1522 PetscCall(VecDestroy(&acown)); 1523 } else { 1524 const char *name; 1525 PetscInt *sizes, *hybsizes, *ghostsizes; 1526 PetscInt locDepth, depth, cellHeight, dim, d; 1527 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1528 PetscInt numLabels, l, maxSize = 17; 1529 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1530 MPI_Comm comm; 1531 PetscMPIInt size, rank; 1532 1533 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1534 PetscCallMPI(MPI_Comm_size(comm, &size)); 1535 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1536 PetscCall(DMGetDimension(dm, &dim)); 1537 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1538 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1539 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1540 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1541 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1542 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1543 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1544 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1545 gcNum = gcEnd - gcStart; 1546 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1547 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1548 for (d = 0; d <= depth; d++) { 1549 PetscInt Nc[2] = {0, 0}, ict; 1550 1551 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1552 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1553 ict = ct0; 1554 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1555 ct0 = (DMPolytopeType)ict; 1556 for (p = pStart; p < pEnd; ++p) { 1557 DMPolytopeType ct; 1558 1559 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1560 if (ct == ct0) ++Nc[0]; 1561 else ++Nc[1]; 1562 } 1563 if (size < maxSize) { 1564 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1565 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1566 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1567 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1568 for (p = 0; p < size; ++p) { 1569 if (rank == 0) { 1570 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1571 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1572 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1573 } 1574 } 1575 } else { 1576 PetscInt locMinMax[2]; 1577 1578 locMinMax[0] = Nc[0] + Nc[1]; 1579 locMinMax[1] = Nc[0] + Nc[1]; 1580 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1581 locMinMax[0] = Nc[1]; 1582 locMinMax[1] = Nc[1]; 1583 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1584 if (d == depth) { 1585 locMinMax[0] = gcNum; 1586 locMinMax[1] = gcNum; 1587 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1588 } 1589 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1591 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1592 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1593 } 1594 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1595 } 1596 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1597 { 1598 const PetscReal *maxCell; 1599 const PetscReal *L; 1600 PetscBool localized; 1601 1602 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1603 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1604 if (L || localized) { 1605 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1606 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1607 if (L) { 1608 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1609 for (d = 0; d < dim; ++d) { 1610 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1611 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1612 } 1613 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1614 } 1615 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1616 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1617 } 1618 } 1619 PetscCall(DMGetNumLabels(dm, &numLabels)); 1620 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1621 for (l = 0; l < numLabels; ++l) { 1622 DMLabel label; 1623 const char *name; 1624 IS valueIS; 1625 const PetscInt *values; 1626 PetscInt numValues, v; 1627 1628 PetscCall(DMGetLabelName(dm, l, &name)); 1629 PetscCall(DMGetLabel(dm, name, &label)); 1630 PetscCall(DMLabelGetNumValues(label, &numValues)); 1631 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1632 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1633 PetscCall(ISGetIndices(valueIS, &values)); 1634 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1635 for (v = 0; v < numValues; ++v) { 1636 PetscInt size; 1637 1638 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1639 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1640 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1641 } 1642 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1643 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1644 PetscCall(ISRestoreIndices(valueIS, &values)); 1645 PetscCall(ISDestroy(&valueIS)); 1646 } 1647 { 1648 char **labelNames; 1649 PetscInt Nl = numLabels; 1650 PetscBool flg; 1651 1652 PetscCall(PetscMalloc1(Nl, &labelNames)); 1653 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1654 for (l = 0; l < Nl; ++l) { 1655 DMLabel label; 1656 1657 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1658 if (flg) { 1659 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1660 PetscCall(DMLabelView(label, viewer)); 1661 } 1662 PetscCall(PetscFree(labelNames[l])); 1663 } 1664 PetscCall(PetscFree(labelNames)); 1665 } 1666 /* If no fields are specified, people do not want to see adjacency */ 1667 if (dm->Nf) { 1668 PetscInt f; 1669 1670 for (f = 0; f < dm->Nf; ++f) { 1671 const char *name; 1672 1673 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1674 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1675 PetscCall(PetscViewerASCIIPushTab(viewer)); 1676 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1677 if (dm->fields[f].adjacency[0]) { 1678 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1679 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1680 } else { 1681 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1682 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1683 } 1684 PetscCall(PetscViewerASCIIPopTab(viewer)); 1685 } 1686 } 1687 PetscCall(DMGetCoarseDM(dm, &cdm)); 1688 if (cdm) { 1689 PetscCall(PetscViewerASCIIPushTab(viewer)); 1690 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1691 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1692 PetscCall(PetscViewerASCIIPopTab(viewer)); 1693 } 1694 } 1695 PetscFunctionReturn(PETSC_SUCCESS); 1696 } 1697 1698 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1699 { 1700 DMPolytopeType ct; 1701 PetscMPIInt rank; 1702 PetscInt cdim; 1703 1704 PetscFunctionBegin; 1705 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1706 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1707 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1708 switch (ct) { 1709 case DM_POLYTOPE_SEGMENT: 1710 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1711 switch (cdim) { 1712 case 1: { 1713 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1714 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1715 1716 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1719 } break; 1720 case 2: { 1721 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1722 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1723 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1724 1725 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1726 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)); 1727 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)); 1728 } break; 1729 default: 1730 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1731 } 1732 break; 1733 case DM_POLYTOPE_TRIANGLE: 1734 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)); 1735 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1738 break; 1739 case DM_POLYTOPE_QUADRILATERAL: 1740 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)); 1741 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)); 1742 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1746 break; 1747 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1748 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)); 1749 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)); 1750 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1754 break; 1755 case DM_POLYTOPE_FV_GHOST: 1756 break; 1757 default: 1758 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1759 } 1760 PetscFunctionReturn(PETSC_SUCCESS); 1761 } 1762 1763 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1764 { 1765 DMPolytopeType ct; 1766 PetscReal centroid[2] = {0., 0.}; 1767 PetscMPIInt rank; 1768 PetscInt fillColor, v, e, d; 1769 1770 PetscFunctionBegin; 1771 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1772 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1773 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1774 switch (ct) { 1775 case DM_POLYTOPE_TRIANGLE: { 1776 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1777 1778 for (v = 0; v < 3; ++v) { 1779 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1780 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1781 } 1782 for (e = 0; e < 3; ++e) { 1783 refCoords[0] = refVertices[e * 2 + 0]; 1784 refCoords[1] = refVertices[e * 2 + 1]; 1785 for (d = 1; d <= edgeDiv; ++d) { 1786 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1787 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1788 } 1789 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1790 for (d = 0; d < edgeDiv; ++d) { 1791 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)); 1792 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1793 } 1794 } 1795 } break; 1796 default: 1797 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1798 } 1799 PetscFunctionReturn(PETSC_SUCCESS); 1800 } 1801 1802 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1803 { 1804 PetscDraw draw; 1805 DM cdm; 1806 PetscSection coordSection; 1807 Vec coordinates; 1808 PetscReal xyl[3], xyr[3]; 1809 PetscReal *refCoords, *edgeCoords; 1810 PetscBool isnull, drawAffine = PETSC_TRUE; 1811 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1812 1813 PetscFunctionBegin; 1814 PetscCall(DMGetCoordinateDim(dm, &dim)); 1815 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1816 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1817 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1818 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1819 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1820 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1821 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1822 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1823 1824 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1825 PetscCall(PetscDrawIsNull(draw, &isnull)); 1826 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1827 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1828 1829 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1830 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1831 PetscCall(PetscDrawClear(draw)); 1832 1833 for (c = cStart; c < cEnd; ++c) { 1834 PetscScalar *coords = NULL; 1835 const PetscScalar *coords_arr; 1836 PetscInt numCoords; 1837 PetscBool isDG; 1838 1839 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1840 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1841 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1842 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1843 } 1844 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1845 PetscCall(PetscDrawFlush(draw)); 1846 PetscCall(PetscDrawPause(draw)); 1847 PetscCall(PetscDrawSave(draw)); 1848 PetscFunctionReturn(PETSC_SUCCESS); 1849 } 1850 1851 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1852 { 1853 DM odm = dm, rdm = dm, cdm; 1854 PetscFE fe; 1855 PetscSpace sp; 1856 PetscClassId id; 1857 PetscInt degree; 1858 PetscBool hoView = PETSC_TRUE; 1859 1860 PetscFunctionBegin; 1861 PetscObjectOptionsBegin((PetscObject)dm); 1862 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1863 PetscOptionsEnd(); 1864 PetscCall(PetscObjectReference((PetscObject)dm)); 1865 *hdm = dm; 1866 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1867 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1868 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1869 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1870 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1871 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1872 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1873 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1874 DM cdm, rcdm; 1875 Mat In; 1876 Vec cl, rcl; 1877 1878 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1879 if (rd > 1) PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1880 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1881 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1882 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1883 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1884 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1885 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1886 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1887 PetscCall(MatMult(In, cl, rcl)); 1888 PetscCall(MatDestroy(&In)); 1889 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1890 PetscCall(DMDestroy(&odm)); 1891 odm = rdm; 1892 } 1893 *hdm = rdm; 1894 PetscFunctionReturn(PETSC_SUCCESS); 1895 } 1896 1897 #if defined(PETSC_HAVE_EXODUSII) 1898 #include <exodusII.h> 1899 #include <petscviewerexodusii.h> 1900 #endif 1901 1902 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1903 { 1904 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1905 char name[PETSC_MAX_PATH_LEN]; 1906 1907 PetscFunctionBegin; 1908 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1909 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1910 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1911 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1912 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1913 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1914 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1916 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1917 if (iascii) { 1918 PetscViewerFormat format; 1919 PetscCall(PetscViewerGetFormat(viewer, &format)); 1920 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1921 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1922 } else if (ishdf5) { 1923 #if defined(PETSC_HAVE_HDF5) 1924 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1925 #else 1926 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1927 #endif 1928 } else if (isvtk) { 1929 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1930 } else if (isdraw) { 1931 DM hdm; 1932 1933 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1934 PetscCall(DMPlexView_Draw(hdm, viewer)); 1935 PetscCall(DMDestroy(&hdm)); 1936 } else if (isglvis) { 1937 PetscCall(DMPlexView_GLVis(dm, viewer)); 1938 #if defined(PETSC_HAVE_EXODUSII) 1939 } else if (isexodus) { 1940 /* 1941 exodusII requires that all sets be part of exactly one cell set. 1942 If the dm does not have a "Cell Sets" label defined, we create one 1943 with ID 1, containing all cells. 1944 Note that if the Cell Sets label is defined but does not cover all cells, 1945 we may still have a problem. This should probably be checked here or in the viewer; 1946 */ 1947 PetscInt numCS; 1948 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1949 if (!numCS) { 1950 PetscInt cStart, cEnd, c; 1951 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1952 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1953 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1954 } 1955 PetscCall(DMView_PlexExodusII(dm, viewer)); 1956 #endif 1957 #if defined(PETSC_HAVE_CGNS) 1958 } else if (iscgns) { 1959 PetscCall(DMView_PlexCGNS(dm, viewer)); 1960 #endif 1961 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1962 /* Optionally view the partition */ 1963 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1964 if (flg) { 1965 Vec ranks; 1966 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1967 PetscCall(VecView(ranks, viewer)); 1968 PetscCall(VecDestroy(&ranks)); 1969 } 1970 /* Optionally view a label */ 1971 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1972 if (flg) { 1973 DMLabel label; 1974 Vec val; 1975 1976 PetscCall(DMGetLabel(dm, name, &label)); 1977 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1978 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1979 PetscCall(VecView(val, viewer)); 1980 PetscCall(VecDestroy(&val)); 1981 } 1982 PetscFunctionReturn(PETSC_SUCCESS); 1983 } 1984 1985 /*@ 1986 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1987 1988 Collective 1989 1990 Input Parameters: 1991 + dm - The `DM` whose topology is to be saved 1992 - viewer - The `PetscViewer` to save it in 1993 1994 Level: advanced 1995 1996 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1997 @*/ 1998 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1999 { 2000 PetscBool ishdf5; 2001 2002 PetscFunctionBegin; 2003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2004 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2005 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2006 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2007 if (ishdf5) { 2008 #if defined(PETSC_HAVE_HDF5) 2009 PetscViewerFormat format; 2010 PetscCall(PetscViewerGetFormat(viewer, &format)); 2011 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2012 IS globalPointNumbering; 2013 2014 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2015 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2016 PetscCall(ISDestroy(&globalPointNumbering)); 2017 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2018 #else 2019 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2020 #endif 2021 } 2022 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2023 PetscFunctionReturn(PETSC_SUCCESS); 2024 } 2025 2026 /*@ 2027 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2028 2029 Collective 2030 2031 Input Parameters: 2032 + dm - The `DM` whose coordinates are to be saved 2033 - viewer - The `PetscViewer` for saving 2034 2035 Level: advanced 2036 2037 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2038 @*/ 2039 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2040 { 2041 PetscBool ishdf5; 2042 2043 PetscFunctionBegin; 2044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2045 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2046 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2047 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2048 if (ishdf5) { 2049 #if defined(PETSC_HAVE_HDF5) 2050 PetscViewerFormat format; 2051 PetscCall(PetscViewerGetFormat(viewer, &format)); 2052 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2053 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2054 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2055 #else 2056 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2057 #endif 2058 } 2059 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2060 PetscFunctionReturn(PETSC_SUCCESS); 2061 } 2062 2063 /*@ 2064 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2065 2066 Collective 2067 2068 Input Parameters: 2069 + dm - The `DM` whose labels are to be saved 2070 - viewer - The `PetscViewer` for saving 2071 2072 Level: advanced 2073 2074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2075 @*/ 2076 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2077 { 2078 PetscBool ishdf5; 2079 2080 PetscFunctionBegin; 2081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2082 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2083 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2084 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2085 if (ishdf5) { 2086 #if defined(PETSC_HAVE_HDF5) 2087 IS globalPointNumbering; 2088 PetscViewerFormat format; 2089 2090 PetscCall(PetscViewerGetFormat(viewer, &format)); 2091 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2092 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2093 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2094 PetscCall(ISDestroy(&globalPointNumbering)); 2095 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2096 #else 2097 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2098 #endif 2099 } 2100 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2101 PetscFunctionReturn(PETSC_SUCCESS); 2102 } 2103 2104 /*@ 2105 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2106 2107 Collective 2108 2109 Input Parameters: 2110 + dm - The `DM` that contains the topology on which the section to be saved is defined 2111 . viewer - The `PetscViewer` for saving 2112 - sectiondm - The `DM` that contains the section to be saved 2113 2114 Level: advanced 2115 2116 Notes: 2117 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. 2118 2119 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2120 2121 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2122 @*/ 2123 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2124 { 2125 PetscBool ishdf5; 2126 2127 PetscFunctionBegin; 2128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2129 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2130 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2131 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2132 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2133 if (ishdf5) { 2134 #if defined(PETSC_HAVE_HDF5) 2135 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2136 #else 2137 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2138 #endif 2139 } 2140 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2141 PetscFunctionReturn(PETSC_SUCCESS); 2142 } 2143 2144 /*@ 2145 DMPlexGlobalVectorView - Saves a global vector 2146 2147 Collective 2148 2149 Input Parameters: 2150 + dm - The `DM` that represents the topology 2151 . viewer - The `PetscViewer` to save data with 2152 . sectiondm - The `DM` that contains the global section on which vec is defined 2153 - vec - The global vector to be saved 2154 2155 Level: advanced 2156 2157 Notes: 2158 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2159 2160 Calling sequence: 2161 .vb 2162 DMCreate(PETSC_COMM_WORLD, &dm); 2163 DMSetType(dm, DMPLEX); 2164 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2165 DMClone(dm, §iondm); 2166 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2167 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2168 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2169 PetscSectionSetChart(section, pStart, pEnd); 2170 PetscSectionSetUp(section); 2171 DMSetLocalSection(sectiondm, section); 2172 PetscSectionDestroy(§ion); 2173 DMGetGlobalVector(sectiondm, &vec); 2174 PetscObjectSetName((PetscObject)vec, "vec_name"); 2175 DMPlexTopologyView(dm, viewer); 2176 DMPlexSectionView(dm, viewer, sectiondm); 2177 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2178 DMRestoreGlobalVector(sectiondm, &vec); 2179 DMDestroy(§iondm); 2180 DMDestroy(&dm); 2181 .ve 2182 2183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2184 @*/ 2185 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2186 { 2187 PetscBool ishdf5; 2188 2189 PetscFunctionBegin; 2190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2191 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2192 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2193 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2194 /* Check consistency */ 2195 { 2196 PetscSection section; 2197 PetscBool includesConstraints; 2198 PetscInt m, m1; 2199 2200 PetscCall(VecGetLocalSize(vec, &m1)); 2201 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2202 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2203 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2204 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2205 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2206 } 2207 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2208 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2209 if (ishdf5) { 2210 #if defined(PETSC_HAVE_HDF5) 2211 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2212 #else 2213 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2214 #endif 2215 } 2216 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2217 PetscFunctionReturn(PETSC_SUCCESS); 2218 } 2219 2220 /*@ 2221 DMPlexLocalVectorView - Saves a local vector 2222 2223 Collective 2224 2225 Input Parameters: 2226 + dm - The `DM` that represents the topology 2227 . viewer - The `PetscViewer` to save data with 2228 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2229 - vec - The local vector to be saved 2230 2231 Level: advanced 2232 2233 Note: 2234 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2235 2236 Calling sequence: 2237 .vb 2238 DMCreate(PETSC_COMM_WORLD, &dm); 2239 DMSetType(dm, DMPLEX); 2240 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2241 DMClone(dm, §iondm); 2242 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2243 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2244 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2245 PetscSectionSetChart(section, pStart, pEnd); 2246 PetscSectionSetUp(section); 2247 DMSetLocalSection(sectiondm, section); 2248 DMGetLocalVector(sectiondm, &vec); 2249 PetscObjectSetName((PetscObject)vec, "vec_name"); 2250 DMPlexTopologyView(dm, viewer); 2251 DMPlexSectionView(dm, viewer, sectiondm); 2252 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2253 DMRestoreLocalVector(sectiondm, &vec); 2254 DMDestroy(§iondm); 2255 DMDestroy(&dm); 2256 .ve 2257 2258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2259 @*/ 2260 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2261 { 2262 PetscBool ishdf5; 2263 2264 PetscFunctionBegin; 2265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2266 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2267 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2268 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2269 /* Check consistency */ 2270 { 2271 PetscSection section; 2272 PetscBool includesConstraints; 2273 PetscInt m, m1; 2274 2275 PetscCall(VecGetLocalSize(vec, &m1)); 2276 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2277 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2278 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2279 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2280 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2281 } 2282 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2283 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2284 if (ishdf5) { 2285 #if defined(PETSC_HAVE_HDF5) 2286 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2287 #else 2288 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2289 #endif 2290 } 2291 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2292 PetscFunctionReturn(PETSC_SUCCESS); 2293 } 2294 2295 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2296 { 2297 PetscBool ishdf5; 2298 2299 PetscFunctionBegin; 2300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2301 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2302 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2303 if (ishdf5) { 2304 #if defined(PETSC_HAVE_HDF5) 2305 PetscViewerFormat format; 2306 PetscCall(PetscViewerGetFormat(viewer, &format)); 2307 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2308 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2309 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2310 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2311 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2312 PetscFunctionReturn(PETSC_SUCCESS); 2313 #else 2314 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2315 #endif 2316 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2317 } 2318 2319 /*@ 2320 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2321 2322 Collective 2323 2324 Input Parameters: 2325 + dm - The `DM` into which the topology is loaded 2326 - viewer - The `PetscViewer` for the saved topology 2327 2328 Output Parameter: 2329 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded 2330 2331 Level: advanced 2332 2333 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2334 `PetscViewer`, `PetscSF` 2335 @*/ 2336 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2337 { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2344 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2345 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2346 if (ishdf5) { 2347 #if defined(PETSC_HAVE_HDF5) 2348 PetscViewerFormat format; 2349 PetscCall(PetscViewerGetFormat(viewer, &format)); 2350 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2351 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2352 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2353 #else 2354 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2355 #endif 2356 } 2357 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2358 PetscFunctionReturn(PETSC_SUCCESS); 2359 } 2360 2361 /*@ 2362 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2363 2364 Collective 2365 2366 Input Parameters: 2367 + dm - The `DM` into which the coordinates are loaded 2368 . viewer - The `PetscViewer` for the saved coordinates 2369 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2370 2371 Level: advanced 2372 2373 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2374 `PetscSF`, `PetscViewer` 2375 @*/ 2376 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2377 { 2378 PetscBool ishdf5; 2379 2380 PetscFunctionBegin; 2381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2382 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2383 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2384 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2385 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2386 if (ishdf5) { 2387 #if defined(PETSC_HAVE_HDF5) 2388 PetscViewerFormat format; 2389 PetscCall(PetscViewerGetFormat(viewer, &format)); 2390 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2391 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2392 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2393 #else 2394 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2395 #endif 2396 } 2397 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2398 PetscFunctionReturn(PETSC_SUCCESS); 2399 } 2400 2401 /*@ 2402 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2403 2404 Collective 2405 2406 Input Parameters: 2407 + dm - The `DM` into which the labels are loaded 2408 . viewer - The `PetscViewer` for the saved labels 2409 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2410 2411 Level: advanced 2412 2413 Note: 2414 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2415 2416 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2417 `PetscSF`, `PetscViewer` 2418 @*/ 2419 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2420 { 2421 PetscBool ishdf5; 2422 2423 PetscFunctionBegin; 2424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2425 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2426 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2427 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2428 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2429 if (ishdf5) { 2430 #if defined(PETSC_HAVE_HDF5) 2431 PetscViewerFormat format; 2432 2433 PetscCall(PetscViewerGetFormat(viewer, &format)); 2434 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2435 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2436 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2437 #else 2438 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2439 #endif 2440 } 2441 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2442 PetscFunctionReturn(PETSC_SUCCESS); 2443 } 2444 2445 /*@ 2446 DMPlexSectionLoad - Loads section into a `DMPLEX` 2447 2448 Collective 2449 2450 Input Parameters: 2451 + dm - The `DM` that represents the topology 2452 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2453 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2454 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2455 2456 Output Parameters: 2457 + 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) 2458 - 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) 2459 2460 Level: advanced 2461 2462 Notes: 2463 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. 2464 2465 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2466 2467 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. 2468 2469 Example using 2 processes: 2470 .vb 2471 NX (number of points on dm): 4 2472 sectionA : the on-disk section 2473 vecA : a vector associated with sectionA 2474 sectionB : sectiondm's local section constructed in this function 2475 vecB (local) : a vector associated with sectiondm's local section 2476 vecB (global) : a vector associated with sectiondm's global section 2477 2478 rank 0 rank 1 2479 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2480 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2481 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2482 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2483 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2484 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2485 sectionB->atlasDof : 1 0 1 | 1 3 2486 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2487 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2488 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2489 .ve 2490 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2491 2492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2493 @*/ 2494 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2495 { 2496 PetscBool ishdf5; 2497 2498 PetscFunctionBegin; 2499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2500 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2501 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2502 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2503 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2504 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2505 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2506 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2507 if (ishdf5) { 2508 #if defined(PETSC_HAVE_HDF5) 2509 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2510 #else 2511 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2512 #endif 2513 } 2514 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2515 PetscFunctionReturn(PETSC_SUCCESS); 2516 } 2517 2518 /*@ 2519 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2520 2521 Collective 2522 2523 Input Parameters: 2524 + dm - The `DM` that represents the topology 2525 . viewer - The `PetscViewer` that represents the on-disk vector data 2526 . sectiondm - The `DM` that contains the global section on which vec is defined 2527 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2528 - vec - The global vector to set values of 2529 2530 Level: advanced 2531 2532 Notes: 2533 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2534 2535 Calling sequence: 2536 .vb 2537 DMCreate(PETSC_COMM_WORLD, &dm); 2538 DMSetType(dm, DMPLEX); 2539 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2540 DMPlexTopologyLoad(dm, viewer, &sfX); 2541 DMClone(dm, §iondm); 2542 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2543 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2544 DMGetGlobalVector(sectiondm, &vec); 2545 PetscObjectSetName((PetscObject)vec, "vec_name"); 2546 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2547 DMRestoreGlobalVector(sectiondm, &vec); 2548 PetscSFDestroy(&gsf); 2549 PetscSFDestroy(&sfX); 2550 DMDestroy(§iondm); 2551 DMDestroy(&dm); 2552 .ve 2553 2554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2555 `PetscSF`, `PetscViewer` 2556 @*/ 2557 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2558 { 2559 PetscBool ishdf5; 2560 2561 PetscFunctionBegin; 2562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2563 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2564 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2565 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2566 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2567 /* Check consistency */ 2568 { 2569 PetscSection section; 2570 PetscBool includesConstraints; 2571 PetscInt m, m1; 2572 2573 PetscCall(VecGetLocalSize(vec, &m1)); 2574 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2575 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2576 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2577 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2578 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2579 } 2580 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2581 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2582 if (ishdf5) { 2583 #if defined(PETSC_HAVE_HDF5) 2584 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2585 #else 2586 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2587 #endif 2588 } 2589 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2590 PetscFunctionReturn(PETSC_SUCCESS); 2591 } 2592 2593 /*@ 2594 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2595 2596 Collective 2597 2598 Input Parameters: 2599 + dm - The `DM` that represents the topology 2600 . viewer - The `PetscViewer` that represents the on-disk vector data 2601 . sectiondm - The `DM` that contains the local section on which vec is defined 2602 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2603 - vec - The local vector to set values of 2604 2605 Level: advanced 2606 2607 Notes: 2608 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2609 2610 Calling sequence: 2611 .vb 2612 DMCreate(PETSC_COMM_WORLD, &dm); 2613 DMSetType(dm, DMPLEX); 2614 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2615 DMPlexTopologyLoad(dm, viewer, &sfX); 2616 DMClone(dm, §iondm); 2617 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2618 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2619 DMGetLocalVector(sectiondm, &vec); 2620 PetscObjectSetName((PetscObject)vec, "vec_name"); 2621 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2622 DMRestoreLocalVector(sectiondm, &vec); 2623 PetscSFDestroy(&lsf); 2624 PetscSFDestroy(&sfX); 2625 DMDestroy(§iondm); 2626 DMDestroy(&dm); 2627 .ve 2628 2629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2630 `PetscSF`, `PetscViewer` 2631 @*/ 2632 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2633 { 2634 PetscBool ishdf5; 2635 2636 PetscFunctionBegin; 2637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2638 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2639 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2640 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2641 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2642 /* Check consistency */ 2643 { 2644 PetscSection section; 2645 PetscBool includesConstraints; 2646 PetscInt m, m1; 2647 2648 PetscCall(VecGetLocalSize(vec, &m1)); 2649 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2650 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2651 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2652 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2653 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2654 } 2655 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2656 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2657 if (ishdf5) { 2658 #if defined(PETSC_HAVE_HDF5) 2659 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2660 #else 2661 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2662 #endif 2663 } 2664 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2665 PetscFunctionReturn(PETSC_SUCCESS); 2666 } 2667 2668 PetscErrorCode DMDestroy_Plex(DM dm) 2669 { 2670 DM_Plex *mesh = (DM_Plex *)dm->data; 2671 2672 PetscFunctionBegin; 2673 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2674 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2675 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2676 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2677 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2678 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2679 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2680 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2681 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2682 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2683 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2684 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2685 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2686 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2687 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2688 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2689 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2690 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2691 PetscCall(PetscFree(mesh->cones)); 2692 PetscCall(PetscFree(mesh->coneOrientations)); 2693 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2694 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2695 PetscCall(PetscFree(mesh->supports)); 2696 PetscCall(PetscFree(mesh->cellTypes)); 2697 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2698 PetscCall(PetscFree(mesh->tetgenOpts)); 2699 PetscCall(PetscFree(mesh->triangleOpts)); 2700 PetscCall(PetscFree(mesh->transformType)); 2701 PetscCall(PetscFree(mesh->distributionName)); 2702 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2703 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2704 PetscCall(ISDestroy(&mesh->subpointIS)); 2705 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2706 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2707 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2708 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2709 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2710 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2711 PetscCall(ISDestroy(&mesh->anchorIS)); 2712 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2713 PetscCall(PetscFree(mesh->parents)); 2714 PetscCall(PetscFree(mesh->childIDs)); 2715 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2716 PetscCall(PetscFree(mesh->children)); 2717 PetscCall(DMDestroy(&mesh->referenceTree)); 2718 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2719 PetscCall(PetscFree(mesh->neighbors)); 2720 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2721 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2722 PetscCall(PetscFree(mesh)); 2723 PetscFunctionReturn(PETSC_SUCCESS); 2724 } 2725 2726 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2727 { 2728 PetscSection sectionGlobal; 2729 PetscInt bs = -1, mbs; 2730 PetscInt localSize, localStart = 0; 2731 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2732 MatType mtype; 2733 ISLocalToGlobalMapping ltog; 2734 2735 PetscFunctionBegin; 2736 PetscCall(MatInitializePackage()); 2737 mtype = dm->mattype; 2738 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2739 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2740 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2741 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2742 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2743 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2744 PetscCall(MatSetType(*J, mtype)); 2745 PetscCall(MatSetFromOptions(*J)); 2746 PetscCall(MatGetBlockSize(*J, &mbs)); 2747 if (mbs > 1) bs = mbs; 2748 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2749 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2750 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2751 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2752 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2753 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2754 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2755 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2756 if (!isShell) { 2757 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2758 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2759 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2760 2761 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2762 2763 PetscCall(PetscCalloc1(localSize, &pblocks)); 2764 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2765 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2766 for (p = pStart; p < pEnd; ++p) { 2767 switch (dm->blocking_type) { 2768 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2769 PetscInt bdof, offset; 2770 2771 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2772 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2773 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2774 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2775 dof = dof < 0 ? -(dof + 1) : dof; 2776 bdof = cdof && (dof - cdof) ? 1 : dof; 2777 if (dof) { 2778 if (bs < 0) { 2779 bs = bdof; 2780 } else if (bs != bdof) { 2781 bs = 1; 2782 } 2783 } 2784 } break; 2785 case DM_BLOCKING_FIELD_NODE: { 2786 for (PetscInt field = 0; field < num_fields; field++) { 2787 PetscInt num_comp, bdof, offset; 2788 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2789 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2790 if (dof < 0) continue; 2791 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2792 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2793 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); 2794 PetscInt num_nodes = dof / num_comp; 2795 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2796 // Handle possibly constant block size (unlikely) 2797 bdof = cdof && (dof - cdof) ? 1 : dof; 2798 if (dof) { 2799 if (bs < 0) { 2800 bs = bdof; 2801 } else if (bs != bdof) { 2802 bs = 1; 2803 } 2804 } 2805 } 2806 } break; 2807 } 2808 } 2809 /* Must have same blocksize on all procs (some might have no points) */ 2810 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2811 bsLocal[1] = bs; 2812 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2813 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2814 else bs = bsMinMax[0]; 2815 bs = PetscMax(1, bs); 2816 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2817 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2818 PetscCall(MatSetBlockSize(*J, bs)); 2819 PetscCall(MatSetUp(*J)); 2820 } else { 2821 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2822 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2823 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2824 } 2825 { // Consolidate blocks 2826 PetscInt nblocks = 0; 2827 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2828 if (pblocks[i] == 0) continue; 2829 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2830 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2831 } 2832 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2833 } 2834 PetscCall(PetscFree(pblocks)); 2835 } 2836 PetscCall(MatSetDM(*J, dm)); 2837 PetscFunctionReturn(PETSC_SUCCESS); 2838 } 2839 2840 /*@ 2841 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2842 2843 Not Collective 2844 2845 Input Parameter: 2846 . dm - The `DMPLEX` 2847 2848 Output Parameter: 2849 . subsection - The subdomain section 2850 2851 Level: developer 2852 2853 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2854 @*/ 2855 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2856 { 2857 DM_Plex *mesh = (DM_Plex *)dm->data; 2858 2859 PetscFunctionBegin; 2860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2861 if (!mesh->subdomainSection) { 2862 PetscSection section; 2863 PetscSF sf; 2864 2865 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2866 PetscCall(DMGetLocalSection(dm, §ion)); 2867 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2868 PetscCall(PetscSFDestroy(&sf)); 2869 } 2870 *subsection = mesh->subdomainSection; 2871 PetscFunctionReturn(PETSC_SUCCESS); 2872 } 2873 2874 /*@ 2875 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2876 2877 Not Collective 2878 2879 Input Parameter: 2880 . dm - The `DMPLEX` 2881 2882 Output Parameters: 2883 + pStart - The first mesh point 2884 - pEnd - The upper bound for mesh points 2885 2886 Level: beginner 2887 2888 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2889 @*/ 2890 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2891 { 2892 DM_Plex *mesh = (DM_Plex *)dm->data; 2893 2894 PetscFunctionBegin; 2895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2896 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2897 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2898 PetscFunctionReturn(PETSC_SUCCESS); 2899 } 2900 2901 /*@ 2902 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2903 2904 Not Collective 2905 2906 Input Parameters: 2907 + dm - The `DMPLEX` 2908 . pStart - The first mesh point 2909 - pEnd - The upper bound for mesh points 2910 2911 Level: beginner 2912 2913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2914 @*/ 2915 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2916 { 2917 DM_Plex *mesh = (DM_Plex *)dm->data; 2918 2919 PetscFunctionBegin; 2920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2921 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2922 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2923 PetscCall(PetscFree(mesh->cellTypes)); 2924 PetscFunctionReturn(PETSC_SUCCESS); 2925 } 2926 2927 /*@ 2928 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2929 2930 Not Collective 2931 2932 Input Parameters: 2933 + dm - The `DMPLEX` 2934 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2935 2936 Output Parameter: 2937 . size - The cone size for point `p` 2938 2939 Level: beginner 2940 2941 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2942 @*/ 2943 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2944 { 2945 DM_Plex *mesh = (DM_Plex *)dm->data; 2946 2947 PetscFunctionBegin; 2948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2949 PetscAssertPointer(size, 3); 2950 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2951 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2952 PetscFunctionReturn(PETSC_SUCCESS); 2953 } 2954 2955 /*@ 2956 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2957 2958 Not Collective 2959 2960 Input Parameters: 2961 + dm - The `DMPLEX` 2962 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2963 - size - The cone size for point `p` 2964 2965 Level: beginner 2966 2967 Note: 2968 This should be called after `DMPlexSetChart()`. 2969 2970 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2971 @*/ 2972 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2973 { 2974 DM_Plex *mesh = (DM_Plex *)dm->data; 2975 2976 PetscFunctionBegin; 2977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2978 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2979 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2980 PetscFunctionReturn(PETSC_SUCCESS); 2981 } 2982 2983 /*@C 2984 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2985 2986 Not Collective 2987 2988 Input Parameters: 2989 + dm - The `DMPLEX` 2990 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2991 2992 Output Parameter: 2993 . cone - An array of points which are on the in-edges for point `p` 2994 2995 Level: beginner 2996 2997 Fortran Notes: 2998 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2999 `DMPlexRestoreCone()` is not needed/available in C. 3000 3001 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3002 @*/ 3003 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3004 { 3005 DM_Plex *mesh = (DM_Plex *)dm->data; 3006 PetscInt off; 3007 3008 PetscFunctionBegin; 3009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3010 PetscAssertPointer(cone, 3); 3011 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3012 *cone = &mesh->cones[off]; 3013 PetscFunctionReturn(PETSC_SUCCESS); 3014 } 3015 3016 /*@C 3017 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3018 3019 Not Collective 3020 3021 Input Parameters: 3022 + dm - The `DMPLEX` 3023 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3024 3025 Output Parameters: 3026 + pConesSection - `PetscSection` describing the layout of `pCones` 3027 - pCones - An array of points which are on the in-edges for the point set `p` 3028 3029 Level: intermediate 3030 3031 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3032 @*/ 3033 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3034 { 3035 PetscSection cs, newcs; 3036 PetscInt *cones; 3037 PetscInt *newarr = NULL; 3038 PetscInt n; 3039 3040 PetscFunctionBegin; 3041 PetscCall(DMPlexGetCones(dm, &cones)); 3042 PetscCall(DMPlexGetConeSection(dm, &cs)); 3043 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3044 if (pConesSection) *pConesSection = newcs; 3045 if (pCones) { 3046 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3047 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3048 } 3049 PetscFunctionReturn(PETSC_SUCCESS); 3050 } 3051 3052 /*@ 3053 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3054 3055 Not Collective 3056 3057 Input Parameters: 3058 + dm - The `DMPLEX` 3059 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3060 3061 Output Parameter: 3062 . expandedPoints - An array of vertices recursively expanded from input points 3063 3064 Level: advanced 3065 3066 Notes: 3067 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3068 3069 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3070 3071 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3072 `DMPlexGetDepth()`, `IS` 3073 @*/ 3074 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3075 { 3076 IS *expandedPointsAll; 3077 PetscInt depth; 3078 3079 PetscFunctionBegin; 3080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3081 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3082 PetscAssertPointer(expandedPoints, 3); 3083 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3084 *expandedPoints = expandedPointsAll[0]; 3085 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3086 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3087 PetscFunctionReturn(PETSC_SUCCESS); 3088 } 3089 3090 /*@ 3091 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 3092 3093 Not Collective 3094 3095 Input Parameters: 3096 + dm - The `DMPLEX` 3097 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3098 3099 Output Parameters: 3100 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3101 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3102 - sections - (optional) An array of sections which describe mappings from points to their cone points 3103 3104 Level: advanced 3105 3106 Notes: 3107 Like `DMPlexGetConeTuple()` but recursive. 3108 3109 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. 3110 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3111 3112 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\: 3113 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3114 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3115 3116 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3117 `DMPlexGetDepth()`, `PetscSection`, `IS` 3118 @*/ 3119 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3120 { 3121 const PetscInt *arr0 = NULL, *cone = NULL; 3122 PetscInt *arr = NULL, *newarr = NULL; 3123 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3124 IS *expandedPoints_; 3125 PetscSection *sections_; 3126 3127 PetscFunctionBegin; 3128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3129 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3130 if (depth) PetscAssertPointer(depth, 3); 3131 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3132 if (sections) PetscAssertPointer(sections, 5); 3133 PetscCall(ISGetLocalSize(points, &n)); 3134 PetscCall(ISGetIndices(points, &arr0)); 3135 PetscCall(DMPlexGetDepth(dm, &depth_)); 3136 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3137 PetscCall(PetscCalloc1(depth_, §ions_)); 3138 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3139 for (d = depth_ - 1; d >= 0; d--) { 3140 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3141 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3142 for (i = 0; i < n; i++) { 3143 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3144 if (arr[i] >= start && arr[i] < end) { 3145 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3146 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3147 } else { 3148 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3149 } 3150 } 3151 PetscCall(PetscSectionSetUp(sections_[d])); 3152 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3153 PetscCall(PetscMalloc1(newn, &newarr)); 3154 for (i = 0; i < n; i++) { 3155 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3156 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3157 if (cn > 1) { 3158 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3159 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3160 } else { 3161 newarr[co] = arr[i]; 3162 } 3163 } 3164 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3165 arr = newarr; 3166 n = newn; 3167 } 3168 PetscCall(ISRestoreIndices(points, &arr0)); 3169 *depth = depth_; 3170 if (expandedPoints) *expandedPoints = expandedPoints_; 3171 else { 3172 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3173 PetscCall(PetscFree(expandedPoints_)); 3174 } 3175 if (sections) *sections = sections_; 3176 else { 3177 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3178 PetscCall(PetscFree(sections_)); 3179 } 3180 PetscFunctionReturn(PETSC_SUCCESS); 3181 } 3182 3183 /*@ 3184 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3185 3186 Not Collective 3187 3188 Input Parameters: 3189 + dm - The `DMPLEX` 3190 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3191 3192 Output Parameters: 3193 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3194 . expandedPoints - (optional) An array of recursively expanded cones 3195 - sections - (optional) An array of sections which describe mappings from points to their cone points 3196 3197 Level: advanced 3198 3199 Note: 3200 See `DMPlexGetConeRecursive()` 3201 3202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3203 `DMPlexGetDepth()`, `IS`, `PetscSection` 3204 @*/ 3205 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3206 { 3207 PetscInt d, depth_; 3208 3209 PetscFunctionBegin; 3210 PetscCall(DMPlexGetDepth(dm, &depth_)); 3211 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3212 if (depth) *depth = 0; 3213 if (expandedPoints) { 3214 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3215 PetscCall(PetscFree(*expandedPoints)); 3216 } 3217 if (sections) { 3218 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3219 PetscCall(PetscFree(*sections)); 3220 } 3221 PetscFunctionReturn(PETSC_SUCCESS); 3222 } 3223 3224 /*@ 3225 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 3226 3227 Not Collective 3228 3229 Input Parameters: 3230 + dm - The `DMPLEX` 3231 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3232 - cone - An array of points which are on the in-edges for point `p` 3233 3234 Level: beginner 3235 3236 Note: 3237 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3238 3239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3240 @*/ 3241 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3242 { 3243 DM_Plex *mesh = (DM_Plex *)dm->data; 3244 PetscInt dof, off, c; 3245 3246 PetscFunctionBegin; 3247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3248 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3249 if (dof) PetscAssertPointer(cone, 3); 3250 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3251 if (PetscDefined(USE_DEBUG)) { 3252 PetscInt pStart, pEnd; 3253 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3254 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); 3255 for (c = 0; c < dof; ++c) { 3256 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); 3257 mesh->cones[off + c] = cone[c]; 3258 } 3259 } else { 3260 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3261 } 3262 PetscFunctionReturn(PETSC_SUCCESS); 3263 } 3264 3265 /*@C 3266 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3267 3268 Not Collective 3269 3270 Input Parameters: 3271 + dm - The `DMPLEX` 3272 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3273 3274 Output Parameter: 3275 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3276 integer giving the prescription for cone traversal. 3277 3278 Level: beginner 3279 3280 Note: 3281 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3282 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3283 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3284 with the identity. 3285 3286 Fortran Notes: 3287 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3288 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3289 3290 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3291 @*/ 3292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3293 { 3294 DM_Plex *mesh = (DM_Plex *)dm->data; 3295 PetscInt off; 3296 3297 PetscFunctionBegin; 3298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3299 if (PetscDefined(USE_DEBUG)) { 3300 PetscInt dof; 3301 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3302 if (dof) PetscAssertPointer(coneOrientation, 3); 3303 } 3304 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3305 3306 *coneOrientation = &mesh->coneOrientations[off]; 3307 PetscFunctionReturn(PETSC_SUCCESS); 3308 } 3309 3310 /*@ 3311 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3312 3313 Not Collective 3314 3315 Input Parameters: 3316 + dm - The `DMPLEX` 3317 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3318 - coneOrientation - An array of orientations 3319 3320 Level: beginner 3321 3322 Notes: 3323 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3324 3325 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3326 3327 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3328 @*/ 3329 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3330 { 3331 DM_Plex *mesh = (DM_Plex *)dm->data; 3332 PetscInt pStart, pEnd; 3333 PetscInt dof, off, c; 3334 3335 PetscFunctionBegin; 3336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3337 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3338 if (dof) PetscAssertPointer(coneOrientation, 3); 3339 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3340 if (PetscDefined(USE_DEBUG)) { 3341 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3342 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); 3343 for (c = 0; c < dof; ++c) { 3344 PetscInt cdof, o = coneOrientation[c]; 3345 3346 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3347 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); 3348 mesh->coneOrientations[off + c] = o; 3349 } 3350 } else { 3351 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3352 } 3353 PetscFunctionReturn(PETSC_SUCCESS); 3354 } 3355 3356 /*@ 3357 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3358 3359 Not Collective 3360 3361 Input Parameters: 3362 + dm - The `DMPLEX` 3363 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3364 . conePos - The local index in the cone where the point should be put 3365 - conePoint - The mesh point to insert 3366 3367 Level: beginner 3368 3369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3370 @*/ 3371 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3372 { 3373 DM_Plex *mesh = (DM_Plex *)dm->data; 3374 PetscInt pStart, pEnd; 3375 PetscInt dof, off; 3376 3377 PetscFunctionBegin; 3378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3379 if (PetscDefined(USE_DEBUG)) { 3380 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3381 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); 3382 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); 3383 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3384 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); 3385 } 3386 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3387 mesh->cones[off + conePos] = conePoint; 3388 PetscFunctionReturn(PETSC_SUCCESS); 3389 } 3390 3391 /*@ 3392 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3393 3394 Not Collective 3395 3396 Input Parameters: 3397 + dm - The `DMPLEX` 3398 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3399 . conePos - The local index in the cone where the point should be put 3400 - coneOrientation - The point orientation to insert 3401 3402 Level: beginner 3403 3404 Note: 3405 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3406 3407 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3408 @*/ 3409 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3410 { 3411 DM_Plex *mesh = (DM_Plex *)dm->data; 3412 PetscInt pStart, pEnd; 3413 PetscInt dof, off; 3414 3415 PetscFunctionBegin; 3416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3417 if (PetscDefined(USE_DEBUG)) { 3418 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3419 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); 3420 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3421 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); 3422 } 3423 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3424 mesh->coneOrientations[off + conePos] = coneOrientation; 3425 PetscFunctionReturn(PETSC_SUCCESS); 3426 } 3427 3428 /*@C 3429 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3430 3431 Not collective 3432 3433 Input Parameters: 3434 + dm - The DMPlex 3435 - p - The point, which must lie in the chart set with DMPlexSetChart() 3436 3437 Output Parameters: 3438 + cone - An array of points which are on the in-edges for point `p` 3439 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3440 integer giving the prescription for cone traversal. 3441 3442 Level: beginner 3443 3444 Notes: 3445 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3446 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3447 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3448 with the identity. 3449 3450 Fortran Notes: 3451 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3452 `DMPlexRestoreCone()` is not needed/available in C. 3453 3454 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3455 @*/ 3456 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3457 { 3458 DM_Plex *mesh = (DM_Plex *)dm->data; 3459 3460 PetscFunctionBegin; 3461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3462 if (mesh->tr) { 3463 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3464 } else { 3465 PetscInt off; 3466 if (PetscDefined(USE_DEBUG)) { 3467 PetscInt dof; 3468 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3469 if (dof) { 3470 if (cone) PetscAssertPointer(cone, 3); 3471 if (ornt) PetscAssertPointer(ornt, 4); 3472 } 3473 } 3474 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3475 if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB 3476 if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL; 3477 } 3478 PetscFunctionReturn(PETSC_SUCCESS); 3479 } 3480 3481 /*@C 3482 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3483 3484 Not Collective 3485 3486 Input Parameters: 3487 + dm - The DMPlex 3488 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3489 . cone - An array of points which are on the in-edges for point p 3490 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3491 integer giving the prescription for cone traversal. 3492 3493 Level: beginner 3494 3495 Notes: 3496 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3497 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3498 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3499 with the identity. 3500 3501 Fortran Notes: 3502 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3503 `DMPlexRestoreCone()` is not needed/available in C. 3504 3505 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3506 @*/ 3507 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3508 { 3509 DM_Plex *mesh = (DM_Plex *)dm->data; 3510 3511 PetscFunctionBegin; 3512 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3513 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3514 PetscFunctionReturn(PETSC_SUCCESS); 3515 } 3516 3517 /*@ 3518 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3519 3520 Not Collective 3521 3522 Input Parameters: 3523 + dm - The `DMPLEX` 3524 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3525 3526 Output Parameter: 3527 . size - The support size for point `p` 3528 3529 Level: beginner 3530 3531 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3532 @*/ 3533 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3534 { 3535 DM_Plex *mesh = (DM_Plex *)dm->data; 3536 3537 PetscFunctionBegin; 3538 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3539 PetscAssertPointer(size, 3); 3540 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3541 PetscFunctionReturn(PETSC_SUCCESS); 3542 } 3543 3544 /*@ 3545 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3546 3547 Not Collective 3548 3549 Input Parameters: 3550 + dm - The `DMPLEX` 3551 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3552 - size - The support size for point `p` 3553 3554 Level: beginner 3555 3556 Note: 3557 This should be called after `DMPlexSetChart()`. 3558 3559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3560 @*/ 3561 PetscErrorCode DMPlexSetSupportSize(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 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3568 PetscFunctionReturn(PETSC_SUCCESS); 3569 } 3570 3571 /*@C 3572 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3573 3574 Not Collective 3575 3576 Input Parameters: 3577 + dm - The `DMPLEX` 3578 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3579 3580 Output Parameter: 3581 . support - An array of points which are on the out-edges for point `p` 3582 3583 Level: beginner 3584 3585 Fortran Notes: 3586 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3587 `DMPlexRestoreSupport()` is not needed/available in C. 3588 3589 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3590 @*/ 3591 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3592 { 3593 DM_Plex *mesh = (DM_Plex *)dm->data; 3594 PetscInt off; 3595 3596 PetscFunctionBegin; 3597 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3598 PetscAssertPointer(support, 3); 3599 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3600 *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB 3601 PetscFunctionReturn(PETSC_SUCCESS); 3602 } 3603 3604 /*@ 3605 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3606 3607 Not Collective 3608 3609 Input Parameters: 3610 + dm - The `DMPLEX` 3611 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3612 - support - An array of points which are on the out-edges for point `p` 3613 3614 Level: beginner 3615 3616 Note: 3617 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3618 3619 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3620 @*/ 3621 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3622 { 3623 DM_Plex *mesh = (DM_Plex *)dm->data; 3624 PetscInt pStart, pEnd; 3625 PetscInt dof, off, c; 3626 3627 PetscFunctionBegin; 3628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3629 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3630 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3631 if (dof) PetscAssertPointer(support, 3); 3632 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3633 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); 3634 for (c = 0; c < dof; ++c) { 3635 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); 3636 mesh->supports[off + c] = support[c]; 3637 } 3638 PetscFunctionReturn(PETSC_SUCCESS); 3639 } 3640 3641 /*@ 3642 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3643 3644 Not Collective 3645 3646 Input Parameters: 3647 + dm - The `DMPLEX` 3648 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3649 . supportPos - The local index in the cone where the point should be put 3650 - supportPoint - The mesh point to insert 3651 3652 Level: beginner 3653 3654 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3655 @*/ 3656 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3657 { 3658 DM_Plex *mesh = (DM_Plex *)dm->data; 3659 PetscInt pStart, pEnd; 3660 PetscInt dof, off; 3661 3662 PetscFunctionBegin; 3663 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3664 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3665 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3666 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3667 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); 3668 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); 3669 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); 3670 mesh->supports[off + supportPos] = supportPoint; 3671 PetscFunctionReturn(PETSC_SUCCESS); 3672 } 3673 3674 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3675 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3676 { 3677 switch (ct) { 3678 case DM_POLYTOPE_SEGMENT: 3679 if (o == -1) return -2; 3680 break; 3681 case DM_POLYTOPE_TRIANGLE: 3682 if (o == -3) return -1; 3683 if (o == -2) return -3; 3684 if (o == -1) return -2; 3685 break; 3686 case DM_POLYTOPE_QUADRILATERAL: 3687 if (o == -4) return -2; 3688 if (o == -3) return -1; 3689 if (o == -2) return -4; 3690 if (o == -1) return -3; 3691 break; 3692 default: 3693 return o; 3694 } 3695 return o; 3696 } 3697 3698 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3699 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3700 { 3701 switch (ct) { 3702 case DM_POLYTOPE_SEGMENT: 3703 if ((o == -2) || (o == 1)) return -1; 3704 if (o == -1) return 0; 3705 break; 3706 case DM_POLYTOPE_TRIANGLE: 3707 if (o == -3) return -2; 3708 if (o == -2) return -1; 3709 if (o == -1) return -3; 3710 break; 3711 case DM_POLYTOPE_QUADRILATERAL: 3712 if (o == -4) return -2; 3713 if (o == -3) return -1; 3714 if (o == -2) return -4; 3715 if (o == -1) return -3; 3716 break; 3717 default: 3718 return o; 3719 } 3720 return o; 3721 } 3722 3723 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3724 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3725 { 3726 PetscInt pStart, pEnd, p; 3727 3728 PetscFunctionBegin; 3729 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3730 for (p = pStart; p < pEnd; ++p) { 3731 const PetscInt *cone, *ornt; 3732 PetscInt coneSize, c; 3733 3734 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3735 PetscCall(DMPlexGetCone(dm, p, &cone)); 3736 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3737 for (c = 0; c < coneSize; ++c) { 3738 DMPolytopeType ct; 3739 const PetscInt o = ornt[c]; 3740 3741 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3742 switch (ct) { 3743 case DM_POLYTOPE_SEGMENT: 3744 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3745 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3746 break; 3747 case DM_POLYTOPE_TRIANGLE: 3748 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3749 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3750 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3751 break; 3752 case DM_POLYTOPE_QUADRILATERAL: 3753 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3754 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3755 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3756 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3757 break; 3758 default: 3759 break; 3760 } 3761 } 3762 } 3763 PetscFunctionReturn(PETSC_SUCCESS); 3764 } 3765 3766 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3767 { 3768 DM_Plex *mesh = (DM_Plex *)dm->data; 3769 3770 PetscFunctionBeginHot; 3771 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3772 if (useCone) { 3773 PetscCall(DMPlexGetConeSize(dm, p, size)); 3774 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3775 } else { 3776 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3777 PetscCall(DMPlexGetSupport(dm, p, arr)); 3778 } 3779 } else { 3780 if (useCone) { 3781 const PetscSection s = mesh->coneSection; 3782 const PetscInt ps = p - s->pStart; 3783 const PetscInt off = s->atlasOff[ps]; 3784 3785 *size = s->atlasDof[ps]; 3786 *arr = mesh->cones + off; 3787 *ornt = mesh->coneOrientations + off; 3788 } else { 3789 const PetscSection s = mesh->supportSection; 3790 const PetscInt ps = p - s->pStart; 3791 const PetscInt off = s->atlasOff[ps]; 3792 3793 *size = s->atlasDof[ps]; 3794 *arr = mesh->supports + off; 3795 } 3796 } 3797 PetscFunctionReturn(PETSC_SUCCESS); 3798 } 3799 3800 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3801 { 3802 DM_Plex *mesh = (DM_Plex *)dm->data; 3803 3804 PetscFunctionBeginHot; 3805 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3806 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3807 } 3808 PetscFunctionReturn(PETSC_SUCCESS); 3809 } 3810 3811 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3812 { 3813 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3814 PetscInt *closure; 3815 const PetscInt *tmp = NULL, *tmpO = NULL; 3816 PetscInt off = 0, tmpSize, t; 3817 3818 PetscFunctionBeginHot; 3819 if (ornt) { 3820 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3821 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; 3822 } 3823 if (*points) { 3824 closure = *points; 3825 } else { 3826 PetscInt maxConeSize, maxSupportSize; 3827 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3828 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3829 } 3830 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3831 if (ct == DM_POLYTOPE_UNKNOWN) { 3832 closure[off++] = p; 3833 closure[off++] = 0; 3834 for (t = 0; t < tmpSize; ++t) { 3835 closure[off++] = tmp[t]; 3836 closure[off++] = tmpO ? tmpO[t] : 0; 3837 } 3838 } else { 3839 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3840 3841 /* We assume that cells with a valid type have faces with a valid type */ 3842 closure[off++] = p; 3843 closure[off++] = ornt; 3844 for (t = 0; t < tmpSize; ++t) { 3845 DMPolytopeType ft; 3846 3847 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3848 closure[off++] = tmp[arr[t]]; 3849 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3850 } 3851 } 3852 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3853 if (numPoints) *numPoints = tmpSize + 1; 3854 if (points) *points = closure; 3855 PetscFunctionReturn(PETSC_SUCCESS); 3856 } 3857 3858 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3859 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3860 { 3861 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3862 const PetscInt *cone, *ornt; 3863 PetscInt *pts, *closure = NULL; 3864 DMPolytopeType ft; 3865 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3866 PetscInt dim, coneSize, c, d, clSize, cl; 3867 3868 PetscFunctionBeginHot; 3869 PetscCall(DMGetDimension(dm, &dim)); 3870 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3871 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3872 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3873 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3874 maxSize = PetscMax(coneSeries, supportSeries); 3875 if (*points) { 3876 pts = *points; 3877 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3878 c = 0; 3879 pts[c++] = point; 3880 pts[c++] = o; 3881 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3882 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3883 for (cl = 0; cl < clSize * 2; cl += 2) { 3884 pts[c++] = closure[cl]; 3885 pts[c++] = closure[cl + 1]; 3886 } 3887 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3888 for (cl = 0; cl < clSize * 2; cl += 2) { 3889 pts[c++] = closure[cl]; 3890 pts[c++] = closure[cl + 1]; 3891 } 3892 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3893 for (d = 2; d < coneSize; ++d) { 3894 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3895 pts[c++] = cone[arr[d * 2 + 0]]; 3896 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3897 } 3898 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3899 if (dim >= 3) { 3900 for (d = 2; d < coneSize; ++d) { 3901 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3902 const PetscInt *fcone, *fornt; 3903 PetscInt fconeSize, fc, i; 3904 3905 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3906 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3907 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3908 for (fc = 0; fc < fconeSize; ++fc) { 3909 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3910 const PetscInt co = farr[fc * 2 + 1]; 3911 3912 for (i = 0; i < c; i += 2) 3913 if (pts[i] == cp) break; 3914 if (i == c) { 3915 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3916 pts[c++] = cp; 3917 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3918 } 3919 } 3920 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3921 } 3922 } 3923 *numPoints = c / 2; 3924 *points = pts; 3925 PetscFunctionReturn(PETSC_SUCCESS); 3926 } 3927 3928 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3929 { 3930 DMPolytopeType ct; 3931 PetscInt *closure, *fifo; 3932 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3933 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3934 PetscInt depth, maxSize; 3935 3936 PetscFunctionBeginHot; 3937 PetscCall(DMPlexGetDepth(dm, &depth)); 3938 if (depth == 1) { 3939 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3940 PetscFunctionReturn(PETSC_SUCCESS); 3941 } 3942 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3943 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; 3944 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3945 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3946 PetscFunctionReturn(PETSC_SUCCESS); 3947 } 3948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3949 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3950 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3951 maxSize = PetscMax(coneSeries, supportSeries); 3952 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3953 if (*points) { 3954 closure = *points; 3955 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3956 closure[closureSize++] = p; 3957 closure[closureSize++] = ornt; 3958 fifo[fifoSize++] = p; 3959 fifo[fifoSize++] = ornt; 3960 fifo[fifoSize++] = ct; 3961 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3962 while (fifoSize - fifoStart) { 3963 const PetscInt q = fifo[fifoStart++]; 3964 const PetscInt o = fifo[fifoStart++]; 3965 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3966 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3967 const PetscInt *tmp, *tmpO = NULL; 3968 PetscInt tmpSize, t; 3969 3970 if (PetscDefined(USE_DEBUG)) { 3971 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3972 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); 3973 } 3974 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3975 for (t = 0; t < tmpSize; ++t) { 3976 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3977 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3978 const PetscInt cp = tmp[ip]; 3979 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3980 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3981 PetscInt c; 3982 3983 /* Check for duplicate */ 3984 for (c = 0; c < closureSize; c += 2) { 3985 if (closure[c] == cp) break; 3986 } 3987 if (c == closureSize) { 3988 closure[closureSize++] = cp; 3989 closure[closureSize++] = co; 3990 fifo[fifoSize++] = cp; 3991 fifo[fifoSize++] = co; 3992 fifo[fifoSize++] = ct; 3993 } 3994 } 3995 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3996 } 3997 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3998 if (numPoints) *numPoints = closureSize / 2; 3999 if (points) *points = closure; 4000 PetscFunctionReturn(PETSC_SUCCESS); 4001 } 4002 4003 /*@C 4004 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4005 4006 Not Collective 4007 4008 Input Parameters: 4009 + dm - The `DMPLEX` 4010 . p - The mesh point 4011 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4012 4013 Input/Output Parameter: 4014 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4015 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4016 4017 Output Parameter: 4018 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4019 4020 Level: beginner 4021 4022 Note: 4023 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4024 4025 Fortran Notes: 4026 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4027 4028 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4029 @*/ 4030 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4031 { 4032 PetscFunctionBeginHot; 4033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4034 if (numPoints) PetscAssertPointer(numPoints, 4); 4035 if (points) PetscAssertPointer(points, 5); 4036 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4037 PetscFunctionReturn(PETSC_SUCCESS); 4038 } 4039 4040 /*@C 4041 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4042 4043 Not Collective 4044 4045 Input Parameters: 4046 + dm - The `DMPLEX` 4047 . p - The mesh point 4048 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4049 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4050 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4051 4052 Level: beginner 4053 4054 Note: 4055 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4056 4057 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4058 @*/ 4059 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4060 { 4061 PetscFunctionBeginHot; 4062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4063 if (numPoints) *numPoints = 0; 4064 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4065 PetscFunctionReturn(PETSC_SUCCESS); 4066 } 4067 4068 /*@ 4069 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4070 4071 Not Collective 4072 4073 Input Parameter: 4074 . dm - The `DMPLEX` 4075 4076 Output Parameters: 4077 + maxConeSize - The maximum number of in-edges 4078 - maxSupportSize - The maximum number of out-edges 4079 4080 Level: beginner 4081 4082 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4083 @*/ 4084 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4085 { 4086 DM_Plex *mesh = (DM_Plex *)dm->data; 4087 4088 PetscFunctionBegin; 4089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4090 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4091 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4092 PetscFunctionReturn(PETSC_SUCCESS); 4093 } 4094 4095 PetscErrorCode DMSetUp_Plex(DM dm) 4096 { 4097 DM_Plex *mesh = (DM_Plex *)dm->data; 4098 PetscInt size, maxSupportSize; 4099 4100 PetscFunctionBegin; 4101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4102 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4103 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4104 PetscCall(PetscMalloc1(size, &mesh->cones)); 4105 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4106 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4107 if (maxSupportSize) { 4108 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4109 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4110 PetscCall(PetscMalloc1(size, &mesh->supports)); 4111 } 4112 PetscFunctionReturn(PETSC_SUCCESS); 4113 } 4114 4115 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4116 { 4117 PetscFunctionBegin; 4118 if (subdm) PetscCall(DMClone(dm, subdm)); 4119 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 4120 if (subdm) (*subdm)->useNatural = dm->useNatural; 4121 if (dm->useNatural && dm->sfMigration) { 4122 PetscSF sfNatural; 4123 4124 (*subdm)->sfMigration = dm->sfMigration; 4125 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4126 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4127 (*subdm)->sfNatural = sfNatural; 4128 } 4129 PetscFunctionReturn(PETSC_SUCCESS); 4130 } 4131 4132 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4133 { 4134 PetscInt i = 0; 4135 4136 PetscFunctionBegin; 4137 PetscCall(DMClone(dms[0], superdm)); 4138 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4139 (*superdm)->useNatural = PETSC_FALSE; 4140 for (i = 0; i < len; i++) { 4141 if (dms[i]->useNatural && dms[i]->sfMigration) { 4142 PetscSF sfNatural; 4143 4144 (*superdm)->sfMigration = dms[i]->sfMigration; 4145 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4146 (*superdm)->useNatural = PETSC_TRUE; 4147 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4148 (*superdm)->sfNatural = sfNatural; 4149 break; 4150 } 4151 } 4152 PetscFunctionReturn(PETSC_SUCCESS); 4153 } 4154 4155 /*@ 4156 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4157 4158 Not Collective 4159 4160 Input Parameter: 4161 . dm - The `DMPLEX` 4162 4163 Level: beginner 4164 4165 Note: 4166 This should be called after all calls to `DMPlexSetCone()` 4167 4168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4169 @*/ 4170 PetscErrorCode DMPlexSymmetrize(DM dm) 4171 { 4172 DM_Plex *mesh = (DM_Plex *)dm->data; 4173 PetscInt *offsets; 4174 PetscInt supportSize; 4175 PetscInt pStart, pEnd, p; 4176 4177 PetscFunctionBegin; 4178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4179 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4180 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4181 /* Calculate support sizes */ 4182 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4183 for (p = pStart; p < pEnd; ++p) { 4184 PetscInt dof, off, c; 4185 4186 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4187 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4188 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4189 } 4190 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4191 /* Calculate supports */ 4192 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4193 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4194 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4195 for (p = pStart; p < pEnd; ++p) { 4196 PetscInt dof, off, c; 4197 4198 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4199 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4200 for (c = off; c < off + dof; ++c) { 4201 const PetscInt q = mesh->cones[c]; 4202 PetscInt offS; 4203 4204 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4205 4206 mesh->supports[offS + offsets[q]] = p; 4207 ++offsets[q]; 4208 } 4209 } 4210 PetscCall(PetscFree(offsets)); 4211 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4212 PetscFunctionReturn(PETSC_SUCCESS); 4213 } 4214 4215 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4216 { 4217 IS stratumIS; 4218 4219 PetscFunctionBegin; 4220 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4221 if (PetscDefined(USE_DEBUG)) { 4222 PetscInt qStart, qEnd, numLevels, level; 4223 PetscBool overlap = PETSC_FALSE; 4224 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4225 for (level = 0; level < numLevels; level++) { 4226 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4227 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4228 overlap = PETSC_TRUE; 4229 break; 4230 } 4231 } 4232 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); 4233 } 4234 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4235 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4236 PetscCall(ISDestroy(&stratumIS)); 4237 PetscFunctionReturn(PETSC_SUCCESS); 4238 } 4239 4240 /*@ 4241 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4242 4243 Collective 4244 4245 Input Parameter: 4246 . dm - The `DMPLEX` 4247 4248 Level: beginner 4249 4250 Notes: 4251 The strata group all points of the same grade, and this function calculates the strata. This 4252 grade can be seen as the height (or depth) of the point in the DAG. 4253 4254 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4255 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4256 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4257 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4258 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4259 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4260 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4261 4262 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4263 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4264 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 4265 to interpolate only that one (e0), so that 4266 .vb 4267 cone(c0) = {e0, v2} 4268 cone(e0) = {v0, v1} 4269 .ve 4270 If `DMPlexStratify()` is run on this mesh, it will give depths 4271 .vb 4272 depth 0 = {v0, v1, v2} 4273 depth 1 = {e0, c0} 4274 .ve 4275 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4276 4277 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4278 4279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4280 @*/ 4281 PetscErrorCode DMPlexStratify(DM dm) 4282 { 4283 DM_Plex *mesh = (DM_Plex *)dm->data; 4284 DMLabel label; 4285 PetscInt pStart, pEnd, p; 4286 PetscInt numRoots = 0, numLeaves = 0; 4287 4288 PetscFunctionBegin; 4289 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4290 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4291 4292 /* Create depth label */ 4293 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4294 PetscCall(DMCreateLabel(dm, "depth")); 4295 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4296 4297 { 4298 /* Initialize roots and count leaves */ 4299 PetscInt sMin = PETSC_MAX_INT; 4300 PetscInt sMax = PETSC_MIN_INT; 4301 PetscInt coneSize, supportSize; 4302 4303 for (p = pStart; p < pEnd; ++p) { 4304 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4305 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4306 if (!coneSize && supportSize) { 4307 sMin = PetscMin(p, sMin); 4308 sMax = PetscMax(p, sMax); 4309 ++numRoots; 4310 } else if (!supportSize && coneSize) { 4311 ++numLeaves; 4312 } else if (!supportSize && !coneSize) { 4313 /* Isolated points */ 4314 sMin = PetscMin(p, sMin); 4315 sMax = PetscMax(p, sMax); 4316 } 4317 } 4318 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4319 } 4320 4321 if (numRoots + numLeaves == (pEnd - pStart)) { 4322 PetscInt sMin = PETSC_MAX_INT; 4323 PetscInt sMax = PETSC_MIN_INT; 4324 PetscInt coneSize, supportSize; 4325 4326 for (p = pStart; p < pEnd; ++p) { 4327 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4328 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4329 if (!supportSize && coneSize) { 4330 sMin = PetscMin(p, sMin); 4331 sMax = PetscMax(p, sMax); 4332 } 4333 } 4334 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4335 } else { 4336 PetscInt level = 0; 4337 PetscInt qStart, qEnd, q; 4338 4339 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4340 while (qEnd > qStart) { 4341 PetscInt sMin = PETSC_MAX_INT; 4342 PetscInt sMax = PETSC_MIN_INT; 4343 4344 for (q = qStart; q < qEnd; ++q) { 4345 const PetscInt *support; 4346 PetscInt supportSize, s; 4347 4348 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4349 PetscCall(DMPlexGetSupport(dm, q, &support)); 4350 for (s = 0; s < supportSize; ++s) { 4351 sMin = PetscMin(support[s], sMin); 4352 sMax = PetscMax(support[s], sMax); 4353 } 4354 } 4355 PetscCall(DMLabelGetNumValues(label, &level)); 4356 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4357 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4358 } 4359 } 4360 { /* just in case there is an empty process */ 4361 PetscInt numValues, maxValues = 0, v; 4362 4363 PetscCall(DMLabelGetNumValues(label, &numValues)); 4364 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4365 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4366 } 4367 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4368 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4369 PetscFunctionReturn(PETSC_SUCCESS); 4370 } 4371 4372 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4373 { 4374 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4375 PetscInt dim, depth, pheight, coneSize; 4376 4377 PetscFunctionBeginHot; 4378 PetscCall(DMGetDimension(dm, &dim)); 4379 PetscCall(DMPlexGetDepth(dm, &depth)); 4380 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4381 pheight = depth - pdepth; 4382 if (depth <= 1) { 4383 switch (pdepth) { 4384 case 0: 4385 ct = DM_POLYTOPE_POINT; 4386 break; 4387 case 1: 4388 switch (coneSize) { 4389 case 2: 4390 ct = DM_POLYTOPE_SEGMENT; 4391 break; 4392 case 3: 4393 ct = DM_POLYTOPE_TRIANGLE; 4394 break; 4395 case 4: 4396 switch (dim) { 4397 case 2: 4398 ct = DM_POLYTOPE_QUADRILATERAL; 4399 break; 4400 case 3: 4401 ct = DM_POLYTOPE_TETRAHEDRON; 4402 break; 4403 default: 4404 break; 4405 } 4406 break; 4407 case 5: 4408 ct = DM_POLYTOPE_PYRAMID; 4409 break; 4410 case 6: 4411 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4412 break; 4413 case 8: 4414 ct = DM_POLYTOPE_HEXAHEDRON; 4415 break; 4416 default: 4417 break; 4418 } 4419 } 4420 } else { 4421 if (pdepth == 0) { 4422 ct = DM_POLYTOPE_POINT; 4423 } else if (pheight == 0) { 4424 switch (dim) { 4425 case 1: 4426 switch (coneSize) { 4427 case 2: 4428 ct = DM_POLYTOPE_SEGMENT; 4429 break; 4430 default: 4431 break; 4432 } 4433 break; 4434 case 2: 4435 switch (coneSize) { 4436 case 3: 4437 ct = DM_POLYTOPE_TRIANGLE; 4438 break; 4439 case 4: 4440 ct = DM_POLYTOPE_QUADRILATERAL; 4441 break; 4442 default: 4443 break; 4444 } 4445 break; 4446 case 3: 4447 switch (coneSize) { 4448 case 4: 4449 ct = DM_POLYTOPE_TETRAHEDRON; 4450 break; 4451 case 5: { 4452 const PetscInt *cone; 4453 PetscInt faceConeSize; 4454 4455 PetscCall(DMPlexGetCone(dm, p, &cone)); 4456 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4457 switch (faceConeSize) { 4458 case 3: 4459 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4460 break; 4461 case 4: 4462 ct = DM_POLYTOPE_PYRAMID; 4463 break; 4464 } 4465 } break; 4466 case 6: 4467 ct = DM_POLYTOPE_HEXAHEDRON; 4468 break; 4469 default: 4470 break; 4471 } 4472 break; 4473 default: 4474 break; 4475 } 4476 } else if (pheight > 0) { 4477 switch (coneSize) { 4478 case 2: 4479 ct = DM_POLYTOPE_SEGMENT; 4480 break; 4481 case 3: 4482 ct = DM_POLYTOPE_TRIANGLE; 4483 break; 4484 case 4: 4485 ct = DM_POLYTOPE_QUADRILATERAL; 4486 break; 4487 default: 4488 break; 4489 } 4490 } 4491 } 4492 *pt = ct; 4493 PetscFunctionReturn(PETSC_SUCCESS); 4494 } 4495 4496 /*@ 4497 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4498 4499 Collective 4500 4501 Input Parameter: 4502 . dm - The `DMPLEX` 4503 4504 Level: developer 4505 4506 Note: 4507 This function is normally called automatically when a cell type is requested. It creates an 4508 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4509 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4510 4511 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4512 4513 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4514 @*/ 4515 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4516 { 4517 DM_Plex *mesh; 4518 DMLabel ctLabel; 4519 PetscInt pStart, pEnd, p; 4520 4521 PetscFunctionBegin; 4522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4523 mesh = (DM_Plex *)dm->data; 4524 PetscCall(DMCreateLabel(dm, "celltype")); 4525 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4526 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4527 PetscCall(PetscFree(mesh->cellTypes)); 4528 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4529 for (p = pStart; p < pEnd; ++p) { 4530 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4531 PetscInt pdepth; 4532 4533 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4534 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4535 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4536 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4537 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4538 } 4539 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4540 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4541 PetscFunctionReturn(PETSC_SUCCESS); 4542 } 4543 4544 /*@C 4545 DMPlexGetJoin - Get an array for the join of the set of points 4546 4547 Not Collective 4548 4549 Input Parameters: 4550 + dm - The `DMPLEX` object 4551 . numPoints - The number of input points for the join 4552 - points - The input points 4553 4554 Output Parameters: 4555 + numCoveredPoints - The number of points in the join 4556 - coveredPoints - The points in the join 4557 4558 Level: intermediate 4559 4560 Note: 4561 Currently, this is restricted to a single level join 4562 4563 Fortran Notes: 4564 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4565 4566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4567 @*/ 4568 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4569 { 4570 DM_Plex *mesh = (DM_Plex *)dm->data; 4571 PetscInt *join[2]; 4572 PetscInt joinSize, i = 0; 4573 PetscInt dof, off, p, c, m; 4574 PetscInt maxSupportSize; 4575 4576 PetscFunctionBegin; 4577 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4578 PetscAssertPointer(points, 3); 4579 PetscAssertPointer(numCoveredPoints, 4); 4580 PetscAssertPointer(coveredPoints, 5); 4581 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4582 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4583 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4584 /* Copy in support of first point */ 4585 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4586 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4587 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4588 /* Check each successive support */ 4589 for (p = 1; p < numPoints; ++p) { 4590 PetscInt newJoinSize = 0; 4591 4592 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4593 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4594 for (c = 0; c < dof; ++c) { 4595 const PetscInt point = mesh->supports[off + c]; 4596 4597 for (m = 0; m < joinSize; ++m) { 4598 if (point == join[i][m]) { 4599 join[1 - i][newJoinSize++] = point; 4600 break; 4601 } 4602 } 4603 } 4604 joinSize = newJoinSize; 4605 i = 1 - i; 4606 } 4607 *numCoveredPoints = joinSize; 4608 *coveredPoints = join[i]; 4609 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4610 PetscFunctionReturn(PETSC_SUCCESS); 4611 } 4612 4613 /*@C 4614 DMPlexRestoreJoin - Restore an array for the join of the set of points 4615 4616 Not Collective 4617 4618 Input Parameters: 4619 + dm - The `DMPLEX` object 4620 . numPoints - The number of input points for the join 4621 - points - The input points 4622 4623 Output Parameters: 4624 + numCoveredPoints - The number of points in the join 4625 - coveredPoints - The points in the join 4626 4627 Level: intermediate 4628 4629 Fortran Notes: 4630 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4631 4632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4633 @*/ 4634 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4635 { 4636 PetscFunctionBegin; 4637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4638 if (points) PetscAssertPointer(points, 3); 4639 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4640 PetscAssertPointer(coveredPoints, 5); 4641 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4642 if (numCoveredPoints) *numCoveredPoints = 0; 4643 PetscFunctionReturn(PETSC_SUCCESS); 4644 } 4645 4646 /*@C 4647 DMPlexGetFullJoin - Get an array for the join of the set of points 4648 4649 Not Collective 4650 4651 Input Parameters: 4652 + dm - The `DMPLEX` object 4653 . numPoints - The number of input points for the join 4654 - points - The input points 4655 4656 Output Parameters: 4657 + numCoveredPoints - The number of points in the join 4658 - coveredPoints - The points in the join 4659 4660 Level: intermediate 4661 4662 Fortran Notes: 4663 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4664 4665 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4666 @*/ 4667 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4668 { 4669 PetscInt *offsets, **closures; 4670 PetscInt *join[2]; 4671 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4672 PetscInt p, d, c, m, ms; 4673 4674 PetscFunctionBegin; 4675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4676 PetscAssertPointer(points, 3); 4677 PetscAssertPointer(numCoveredPoints, 4); 4678 PetscAssertPointer(coveredPoints, 5); 4679 4680 PetscCall(DMPlexGetDepth(dm, &depth)); 4681 PetscCall(PetscCalloc1(numPoints, &closures)); 4682 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4683 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4684 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4685 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4686 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4687 4688 for (p = 0; p < numPoints; ++p) { 4689 PetscInt closureSize; 4690 4691 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4692 4693 offsets[p * (depth + 2) + 0] = 0; 4694 for (d = 0; d < depth + 1; ++d) { 4695 PetscInt pStart, pEnd, i; 4696 4697 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4698 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4699 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4700 offsets[p * (depth + 2) + d + 1] = i; 4701 break; 4702 } 4703 } 4704 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4705 } 4706 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); 4707 } 4708 for (d = 0; d < depth + 1; ++d) { 4709 PetscInt dof; 4710 4711 /* Copy in support of first point */ 4712 dof = offsets[d + 1] - offsets[d]; 4713 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4714 /* Check each successive cone */ 4715 for (p = 1; p < numPoints && joinSize; ++p) { 4716 PetscInt newJoinSize = 0; 4717 4718 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4719 for (c = 0; c < dof; ++c) { 4720 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4721 4722 for (m = 0; m < joinSize; ++m) { 4723 if (point == join[i][m]) { 4724 join[1 - i][newJoinSize++] = point; 4725 break; 4726 } 4727 } 4728 } 4729 joinSize = newJoinSize; 4730 i = 1 - i; 4731 } 4732 if (joinSize) break; 4733 } 4734 *numCoveredPoints = joinSize; 4735 *coveredPoints = join[i]; 4736 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4737 PetscCall(PetscFree(closures)); 4738 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4739 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4740 PetscFunctionReturn(PETSC_SUCCESS); 4741 } 4742 4743 /*@C 4744 DMPlexGetMeet - Get an array for the meet of the set of points 4745 4746 Not Collective 4747 4748 Input Parameters: 4749 + dm - The `DMPLEX` object 4750 . numPoints - The number of input points for the meet 4751 - points - The input points 4752 4753 Output Parameters: 4754 + numCoveringPoints - The number of points in the meet 4755 - coveringPoints - The points in the meet 4756 4757 Level: intermediate 4758 4759 Note: 4760 Currently, this is restricted to a single level meet 4761 4762 Fortran Notes: 4763 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4764 4765 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4766 @*/ 4767 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4768 { 4769 DM_Plex *mesh = (DM_Plex *)dm->data; 4770 PetscInt *meet[2]; 4771 PetscInt meetSize, i = 0; 4772 PetscInt dof, off, p, c, m; 4773 PetscInt maxConeSize; 4774 4775 PetscFunctionBegin; 4776 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4777 PetscAssertPointer(points, 3); 4778 PetscAssertPointer(numCoveringPoints, 4); 4779 PetscAssertPointer(coveringPoints, 5); 4780 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4781 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4782 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4783 /* Copy in cone of first point */ 4784 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4785 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4786 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4787 /* Check each successive cone */ 4788 for (p = 1; p < numPoints; ++p) { 4789 PetscInt newMeetSize = 0; 4790 4791 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4792 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4793 for (c = 0; c < dof; ++c) { 4794 const PetscInt point = mesh->cones[off + c]; 4795 4796 for (m = 0; m < meetSize; ++m) { 4797 if (point == meet[i][m]) { 4798 meet[1 - i][newMeetSize++] = point; 4799 break; 4800 } 4801 } 4802 } 4803 meetSize = newMeetSize; 4804 i = 1 - i; 4805 } 4806 *numCoveringPoints = meetSize; 4807 *coveringPoints = meet[i]; 4808 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4809 PetscFunctionReturn(PETSC_SUCCESS); 4810 } 4811 4812 /*@C 4813 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4814 4815 Not Collective 4816 4817 Input Parameters: 4818 + dm - The `DMPLEX` object 4819 . numPoints - The number of input points for the meet 4820 - points - The input points 4821 4822 Output Parameters: 4823 + numCoveredPoints - The number of points in the meet 4824 - coveredPoints - The points in the meet 4825 4826 Level: intermediate 4827 4828 Fortran Notes: 4829 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4830 4831 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4832 @*/ 4833 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4834 { 4835 PetscFunctionBegin; 4836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4837 if (points) PetscAssertPointer(points, 3); 4838 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4839 PetscAssertPointer(coveredPoints, 5); 4840 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4841 if (numCoveredPoints) *numCoveredPoints = 0; 4842 PetscFunctionReturn(PETSC_SUCCESS); 4843 } 4844 4845 /*@C 4846 DMPlexGetFullMeet - Get an array for the meet of the set of points 4847 4848 Not Collective 4849 4850 Input Parameters: 4851 + dm - The `DMPLEX` object 4852 . numPoints - The number of input points for the meet 4853 - points - The input points 4854 4855 Output Parameters: 4856 + numCoveredPoints - The number of points in the meet 4857 - coveredPoints - The points in the meet 4858 4859 Level: intermediate 4860 4861 Fortran Notes: 4862 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4863 4864 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4865 @*/ 4866 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4867 { 4868 PetscInt *offsets, **closures; 4869 PetscInt *meet[2]; 4870 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4871 PetscInt p, h, c, m, mc; 4872 4873 PetscFunctionBegin; 4874 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4875 PetscAssertPointer(points, 3); 4876 PetscAssertPointer(numCoveredPoints, 4); 4877 PetscAssertPointer(coveredPoints, 5); 4878 4879 PetscCall(DMPlexGetDepth(dm, &height)); 4880 PetscCall(PetscMalloc1(numPoints, &closures)); 4881 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4882 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4883 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4884 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4885 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4886 4887 for (p = 0; p < numPoints; ++p) { 4888 PetscInt closureSize; 4889 4890 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4891 4892 offsets[p * (height + 2) + 0] = 0; 4893 for (h = 0; h < height + 1; ++h) { 4894 PetscInt pStart, pEnd, i; 4895 4896 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4897 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4898 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4899 offsets[p * (height + 2) + h + 1] = i; 4900 break; 4901 } 4902 } 4903 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4904 } 4905 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); 4906 } 4907 for (h = 0; h < height + 1; ++h) { 4908 PetscInt dof; 4909 4910 /* Copy in cone of first point */ 4911 dof = offsets[h + 1] - offsets[h]; 4912 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4913 /* Check each successive cone */ 4914 for (p = 1; p < numPoints && meetSize; ++p) { 4915 PetscInt newMeetSize = 0; 4916 4917 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4918 for (c = 0; c < dof; ++c) { 4919 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4920 4921 for (m = 0; m < meetSize; ++m) { 4922 if (point == meet[i][m]) { 4923 meet[1 - i][newMeetSize++] = point; 4924 break; 4925 } 4926 } 4927 } 4928 meetSize = newMeetSize; 4929 i = 1 - i; 4930 } 4931 if (meetSize) break; 4932 } 4933 *numCoveredPoints = meetSize; 4934 *coveredPoints = meet[i]; 4935 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4936 PetscCall(PetscFree(closures)); 4937 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4938 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4939 PetscFunctionReturn(PETSC_SUCCESS); 4940 } 4941 4942 /*@C 4943 DMPlexEqual - Determine if two `DM` have the same topology 4944 4945 Not Collective 4946 4947 Input Parameters: 4948 + dmA - A `DMPLEX` object 4949 - dmB - A `DMPLEX` object 4950 4951 Output Parameter: 4952 . equal - `PETSC_TRUE` if the topologies are identical 4953 4954 Level: intermediate 4955 4956 Note: 4957 We are not solving graph isomorphism, so we do not permute. 4958 4959 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4960 @*/ 4961 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4962 { 4963 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4964 4965 PetscFunctionBegin; 4966 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4967 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4968 PetscAssertPointer(equal, 3); 4969 4970 *equal = PETSC_FALSE; 4971 PetscCall(DMPlexGetDepth(dmA, &depth)); 4972 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4973 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 4974 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4975 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4976 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 4977 for (p = pStart; p < pEnd; ++p) { 4978 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4979 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4980 4981 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4982 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4983 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4984 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4985 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4986 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4987 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4988 for (c = 0; c < coneSize; ++c) { 4989 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4990 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4991 } 4992 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4993 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4994 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4995 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4996 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4997 for (s = 0; s < supportSize; ++s) { 4998 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 4999 } 5000 } 5001 *equal = PETSC_TRUE; 5002 PetscFunctionReturn(PETSC_SUCCESS); 5003 } 5004 5005 /*@C 5006 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5007 5008 Not Collective 5009 5010 Input Parameters: 5011 + dm - The `DMPLEX` 5012 . cellDim - The cell dimension 5013 - numCorners - The number of vertices on a cell 5014 5015 Output Parameter: 5016 . numFaceVertices - The number of vertices on a face 5017 5018 Level: developer 5019 5020 Note: 5021 Of course this can only work for a restricted set of symmetric shapes 5022 5023 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5024 @*/ 5025 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5026 { 5027 MPI_Comm comm; 5028 5029 PetscFunctionBegin; 5030 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5031 PetscAssertPointer(numFaceVertices, 4); 5032 switch (cellDim) { 5033 case 0: 5034 *numFaceVertices = 0; 5035 break; 5036 case 1: 5037 *numFaceVertices = 1; 5038 break; 5039 case 2: 5040 switch (numCorners) { 5041 case 3: /* triangle */ 5042 *numFaceVertices = 2; /* Edge has 2 vertices */ 5043 break; 5044 case 4: /* quadrilateral */ 5045 *numFaceVertices = 2; /* Edge has 2 vertices */ 5046 break; 5047 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5048 *numFaceVertices = 3; /* Edge has 3 vertices */ 5049 break; 5050 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5051 *numFaceVertices = 3; /* Edge has 3 vertices */ 5052 break; 5053 default: 5054 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5055 } 5056 break; 5057 case 3: 5058 switch (numCorners) { 5059 case 4: /* tetradehdron */ 5060 *numFaceVertices = 3; /* Face has 3 vertices */ 5061 break; 5062 case 6: /* tet cohesive cells */ 5063 *numFaceVertices = 4; /* Face has 4 vertices */ 5064 break; 5065 case 8: /* hexahedron */ 5066 *numFaceVertices = 4; /* Face has 4 vertices */ 5067 break; 5068 case 9: /* tet cohesive Lagrange cells */ 5069 *numFaceVertices = 6; /* Face has 6 vertices */ 5070 break; 5071 case 10: /* quadratic tetrahedron */ 5072 *numFaceVertices = 6; /* Face has 6 vertices */ 5073 break; 5074 case 12: /* hex cohesive Lagrange cells */ 5075 *numFaceVertices = 6; /* Face has 6 vertices */ 5076 break; 5077 case 18: /* quadratic tet cohesive Lagrange cells */ 5078 *numFaceVertices = 6; /* Face has 6 vertices */ 5079 break; 5080 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5081 *numFaceVertices = 9; /* Face has 9 vertices */ 5082 break; 5083 default: 5084 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5085 } 5086 break; 5087 default: 5088 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5089 } 5090 PetscFunctionReturn(PETSC_SUCCESS); 5091 } 5092 5093 /*@ 5094 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5095 5096 Not Collective 5097 5098 Input Parameter: 5099 . dm - The `DMPLEX` object 5100 5101 Output Parameter: 5102 . depthLabel - The `DMLabel` recording point depth 5103 5104 Level: developer 5105 5106 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5107 @*/ 5108 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5109 { 5110 PetscFunctionBegin; 5111 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5112 PetscAssertPointer(depthLabel, 2); 5113 *depthLabel = dm->depthLabel; 5114 PetscFunctionReturn(PETSC_SUCCESS); 5115 } 5116 5117 /*@ 5118 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5119 5120 Not Collective 5121 5122 Input Parameter: 5123 . dm - The `DMPLEX` object 5124 5125 Output Parameter: 5126 . depth - The number of strata (breadth first levels) in the DAG 5127 5128 Level: developer 5129 5130 Notes: 5131 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5132 5133 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5134 5135 An empty mesh gives -1. 5136 5137 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5138 @*/ 5139 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5140 { 5141 DM_Plex *mesh = (DM_Plex *)dm->data; 5142 DMLabel label; 5143 PetscInt d = 0; 5144 5145 PetscFunctionBegin; 5146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5147 PetscAssertPointer(depth, 2); 5148 if (mesh->tr) { 5149 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5150 } else { 5151 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5152 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5153 *depth = d - 1; 5154 } 5155 PetscFunctionReturn(PETSC_SUCCESS); 5156 } 5157 5158 /*@ 5159 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5160 5161 Not Collective 5162 5163 Input Parameters: 5164 + dm - The `DMPLEX` object 5165 - depth - The requested depth 5166 5167 Output Parameters: 5168 + start - The first point at this `depth` 5169 - end - One beyond the last point at this `depth` 5170 5171 Level: developer 5172 5173 Notes: 5174 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5175 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5176 higher dimension, e.g., "edges". 5177 5178 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5179 @*/ 5180 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5181 { 5182 DM_Plex *mesh = (DM_Plex *)dm->data; 5183 DMLabel label; 5184 PetscInt pStart, pEnd; 5185 5186 PetscFunctionBegin; 5187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5188 if (start) { 5189 PetscAssertPointer(start, 3); 5190 *start = 0; 5191 } 5192 if (end) { 5193 PetscAssertPointer(end, 4); 5194 *end = 0; 5195 } 5196 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5197 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5198 if (depth < 0) { 5199 if (start) *start = pStart; 5200 if (end) *end = pEnd; 5201 PetscFunctionReturn(PETSC_SUCCESS); 5202 } 5203 if (mesh->tr) { 5204 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5205 } else { 5206 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5207 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5208 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5209 } 5210 PetscFunctionReturn(PETSC_SUCCESS); 5211 } 5212 5213 /*@ 5214 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5215 5216 Not Collective 5217 5218 Input Parameters: 5219 + dm - The `DMPLEX` object 5220 - height - The requested height 5221 5222 Output Parameters: 5223 + start - The first point at this `height` 5224 - end - One beyond the last point at this `height` 5225 5226 Level: developer 5227 5228 Notes: 5229 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5230 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5231 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5232 5233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5234 @*/ 5235 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5236 { 5237 DMLabel label; 5238 PetscInt depth, pStart, pEnd; 5239 5240 PetscFunctionBegin; 5241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5242 if (start) { 5243 PetscAssertPointer(start, 3); 5244 *start = 0; 5245 } 5246 if (end) { 5247 PetscAssertPointer(end, 4); 5248 *end = 0; 5249 } 5250 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5251 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5252 if (height < 0) { 5253 if (start) *start = pStart; 5254 if (end) *end = pEnd; 5255 PetscFunctionReturn(PETSC_SUCCESS); 5256 } 5257 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5258 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5259 else PetscCall(DMGetDimension(dm, &depth)); 5260 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5261 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5262 PetscFunctionReturn(PETSC_SUCCESS); 5263 } 5264 5265 /*@ 5266 DMPlexGetPointDepth - Get the `depth` of a given point 5267 5268 Not Collective 5269 5270 Input Parameters: 5271 + dm - The `DMPLEX` object 5272 - point - The point 5273 5274 Output Parameter: 5275 . depth - The depth of the `point` 5276 5277 Level: intermediate 5278 5279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5280 @*/ 5281 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5282 { 5283 PetscFunctionBegin; 5284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5285 PetscAssertPointer(depth, 3); 5286 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5287 PetscFunctionReturn(PETSC_SUCCESS); 5288 } 5289 5290 /*@ 5291 DMPlexGetPointHeight - Get the `height` of a given point 5292 5293 Not Collective 5294 5295 Input Parameters: 5296 + dm - The `DMPLEX` object 5297 - point - The point 5298 5299 Output Parameter: 5300 . height - The height of the `point` 5301 5302 Level: intermediate 5303 5304 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5305 @*/ 5306 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5307 { 5308 PetscInt n, pDepth; 5309 5310 PetscFunctionBegin; 5311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5312 PetscAssertPointer(height, 3); 5313 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5314 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5315 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5316 PetscFunctionReturn(PETSC_SUCCESS); 5317 } 5318 5319 /*@ 5320 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5321 5322 Not Collective 5323 5324 Input Parameter: 5325 . dm - The `DMPLEX` object 5326 5327 Output Parameter: 5328 . celltypeLabel - The `DMLabel` recording cell polytope type 5329 5330 Level: developer 5331 5332 Note: 5333 This function will trigger automatica computation of cell types. This can be disabled by calling 5334 `DMCreateLabel`(dm, "celltype") beforehand. 5335 5336 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5337 @*/ 5338 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5339 { 5340 PetscFunctionBegin; 5341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5342 PetscAssertPointer(celltypeLabel, 2); 5343 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5344 *celltypeLabel = dm->celltypeLabel; 5345 PetscFunctionReturn(PETSC_SUCCESS); 5346 } 5347 5348 /*@ 5349 DMPlexGetCellType - Get the polytope type of a given cell 5350 5351 Not Collective 5352 5353 Input Parameters: 5354 + dm - The `DMPLEX` object 5355 - cell - The cell 5356 5357 Output Parameter: 5358 . celltype - The polytope type of the cell 5359 5360 Level: intermediate 5361 5362 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5363 @*/ 5364 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5365 { 5366 DM_Plex *mesh = (DM_Plex *)dm->data; 5367 DMLabel label; 5368 PetscInt ct; 5369 5370 PetscFunctionBegin; 5371 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5372 PetscAssertPointer(celltype, 3); 5373 if (mesh->tr) { 5374 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5375 } else { 5376 PetscInt pStart, pEnd; 5377 5378 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5379 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5380 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5381 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5382 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5383 for (PetscInt p = pStart; p < pEnd; p++) { 5384 PetscCall(DMLabelGetValue(label, p, &ct)); 5385 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5386 } 5387 } 5388 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5389 if (PetscDefined(USE_DEBUG)) { 5390 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5391 PetscCall(DMLabelGetValue(label, cell, &ct)); 5392 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5393 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5394 } 5395 } 5396 PetscFunctionReturn(PETSC_SUCCESS); 5397 } 5398 5399 /*@ 5400 DMPlexSetCellType - Set the polytope type of a given cell 5401 5402 Not Collective 5403 5404 Input Parameters: 5405 + dm - The `DMPLEX` object 5406 . cell - The cell 5407 - celltype - The polytope type of the cell 5408 5409 Level: advanced 5410 5411 Note: 5412 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5413 is executed. This function will override the computed type. However, if automatic classification will not succeed 5414 and a user wants to manually specify all types, the classification must be disabled by calling 5415 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5416 5417 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5418 @*/ 5419 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5420 { 5421 DM_Plex *mesh = (DM_Plex *)dm->data; 5422 DMLabel label; 5423 PetscInt pStart, pEnd; 5424 5425 PetscFunctionBegin; 5426 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5427 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5428 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5429 PetscCall(DMLabelSetValue(label, cell, celltype)); 5430 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5431 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5432 PetscFunctionReturn(PETSC_SUCCESS); 5433 } 5434 5435 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5436 { 5437 PetscSection section, s; 5438 Mat m; 5439 PetscInt maxHeight; 5440 const char *prefix; 5441 5442 PetscFunctionBegin; 5443 PetscCall(DMClone(dm, cdm)); 5444 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5445 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5446 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5447 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5448 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5449 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5450 PetscCall(DMSetLocalSection(*cdm, section)); 5451 PetscCall(PetscSectionDestroy(§ion)); 5452 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5453 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5454 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5455 PetscCall(PetscSectionDestroy(&s)); 5456 PetscCall(MatDestroy(&m)); 5457 5458 PetscCall(DMSetNumFields(*cdm, 1)); 5459 PetscCall(DMCreateDS(*cdm)); 5460 (*cdm)->cloneOpts = PETSC_TRUE; 5461 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5462 PetscFunctionReturn(PETSC_SUCCESS); 5463 } 5464 5465 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5466 { 5467 Vec coordsLocal, cellCoordsLocal; 5468 DM coordsDM, cellCoordsDM; 5469 5470 PetscFunctionBegin; 5471 *field = NULL; 5472 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5473 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5474 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5475 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5476 if (coordsLocal && coordsDM) { 5477 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5478 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5479 } 5480 PetscFunctionReturn(PETSC_SUCCESS); 5481 } 5482 5483 /*@C 5484 DMPlexGetConeSection - Return a section which describes the layout of cone data 5485 5486 Not Collective 5487 5488 Input Parameter: 5489 . dm - The `DMPLEX` object 5490 5491 Output Parameter: 5492 . section - The `PetscSection` object 5493 5494 Level: developer 5495 5496 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5497 @*/ 5498 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5499 { 5500 DM_Plex *mesh = (DM_Plex *)dm->data; 5501 5502 PetscFunctionBegin; 5503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5504 if (section) *section = mesh->coneSection; 5505 PetscFunctionReturn(PETSC_SUCCESS); 5506 } 5507 5508 /*@C 5509 DMPlexGetSupportSection - Return a section which describes the layout of support data 5510 5511 Not Collective 5512 5513 Input Parameter: 5514 . dm - The `DMPLEX` object 5515 5516 Output Parameter: 5517 . section - The `PetscSection` object 5518 5519 Level: developer 5520 5521 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5522 @*/ 5523 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5524 { 5525 DM_Plex *mesh = (DM_Plex *)dm->data; 5526 5527 PetscFunctionBegin; 5528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5529 if (section) *section = mesh->supportSection; 5530 PetscFunctionReturn(PETSC_SUCCESS); 5531 } 5532 5533 /*@C 5534 DMPlexGetCones - Return cone data 5535 5536 Not Collective 5537 5538 Input Parameter: 5539 . dm - The `DMPLEX` object 5540 5541 Output Parameter: 5542 . cones - The cone for each point 5543 5544 Level: developer 5545 5546 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5547 @*/ 5548 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5549 { 5550 DM_Plex *mesh = (DM_Plex *)dm->data; 5551 5552 PetscFunctionBegin; 5553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5554 if (cones) *cones = mesh->cones; 5555 PetscFunctionReturn(PETSC_SUCCESS); 5556 } 5557 5558 /*@C 5559 DMPlexGetConeOrientations - Return cone orientation data 5560 5561 Not Collective 5562 5563 Input Parameter: 5564 . dm - The `DMPLEX` object 5565 5566 Output Parameter: 5567 . coneOrientations - The array of cone orientations for all points 5568 5569 Level: developer 5570 5571 Notes: 5572 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5573 5574 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5575 5576 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5577 @*/ 5578 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5579 { 5580 DM_Plex *mesh = (DM_Plex *)dm->data; 5581 5582 PetscFunctionBegin; 5583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5584 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5585 PetscFunctionReturn(PETSC_SUCCESS); 5586 } 5587 5588 /******************************** FEM Support **********************************/ 5589 5590 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5591 { 5592 PetscInt depth; 5593 5594 PetscFunctionBegin; 5595 PetscCall(DMPlexGetDepth(plex, &depth)); 5596 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5597 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5598 PetscFunctionReturn(PETSC_SUCCESS); 5599 } 5600 5601 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5602 { 5603 PetscInt depth; 5604 5605 PetscFunctionBegin; 5606 PetscCall(DMPlexGetDepth(plex, &depth)); 5607 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5608 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5609 PetscFunctionReturn(PETSC_SUCCESS); 5610 } 5611 5612 /* 5613 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5614 representing a line in the section. 5615 */ 5616 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous) 5617 { 5618 PetscObject obj; 5619 PetscClassId id; 5620 PetscFE fe = NULL; 5621 5622 PetscFunctionBeginHot; 5623 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5624 PetscCall(DMGetField(dm, field, NULL, &obj)); 5625 PetscCall(PetscObjectGetClassId(obj, &id)); 5626 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5627 5628 if (!fe) { 5629 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5630 /* An order k SEM disc has k-1 dofs on an edge */ 5631 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5632 *k = *k / *Nc + 1; 5633 } else { 5634 PetscInt dual_space_size, dim; 5635 PetscDualSpace dual_space; 5636 PetscCall(DMGetDimension(dm, &dim)); 5637 PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 5638 PetscCall(PetscDualSpaceGetDimension(dual_space, &dual_space_size)); 5639 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5640 PetscCall(PetscDualSpaceLagrangeGetContinuity(dual_space, continuous)); 5641 } 5642 PetscFunctionReturn(PETSC_SUCCESS); 5643 } 5644 5645 /*@ 5646 5647 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5648 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5649 section provided (or the section of the `DM`). 5650 5651 Input Parameters: 5652 + dm - The `DM` 5653 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5654 - section - The `PetscSection` to reorder, or `NULL` for the default section 5655 5656 Example: 5657 A typical interpolated single-quad mesh might order points as 5658 .vb 5659 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5660 5661 v4 -- e6 -- v3 5662 | | 5663 e7 c0 e8 5664 | | 5665 v1 -- e5 -- v2 5666 .ve 5667 5668 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5669 dofs in the order of points, e.g., 5670 .vb 5671 c0 -> [0,1,2,3] 5672 v1 -> [4] 5673 ... 5674 e5 -> [8, 9] 5675 .ve 5676 5677 which corresponds to the dofs 5678 .vb 5679 6 10 11 7 5680 13 2 3 15 5681 12 0 1 14 5682 4 8 9 5 5683 .ve 5684 5685 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5686 .vb 5687 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5688 .ve 5689 5690 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5691 .vb 5692 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5693 .ve 5694 5695 Level: developer 5696 5697 Notes: 5698 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5699 degree of the basis. 5700 5701 This is required to run with libCEED. 5702 5703 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5704 @*/ 5705 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5706 { 5707 DMLabel label; 5708 PetscInt dim, depth = -1, eStart = -1, Nf; 5709 PetscBool continuous = PETSC_TRUE; 5710 5711 PetscFunctionBegin; 5712 PetscCall(DMGetDimension(dm, &dim)); 5713 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5714 if (point < 0) { 5715 PetscInt sStart, sEnd; 5716 5717 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5718 point = sEnd - sStart ? sStart : point; 5719 } 5720 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5721 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5722 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5723 if (depth == 1) { 5724 eStart = point; 5725 } else if (depth == dim) { 5726 const PetscInt *cone; 5727 5728 PetscCall(DMPlexGetCone(dm, point, &cone)); 5729 if (dim == 2) eStart = cone[0]; 5730 else if (dim == 3) { 5731 const PetscInt *cone2; 5732 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5733 eStart = cone2[0]; 5734 } 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); 5735 } 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); 5736 5737 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5738 for (PetscInt d = 1; d <= dim; d++) { 5739 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5740 PetscInt *perm; 5741 5742 for (f = 0; f < Nf; ++f) { 5743 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5744 size += PetscPowInt(k + 1, d) * Nc; 5745 } 5746 PetscCall(PetscMalloc1(size, &perm)); 5747 for (f = 0; f < Nf; ++f) { 5748 switch (d) { 5749 case 1: 5750 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5751 /* 5752 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5753 We want [ vtx0; edge of length k-1; vtx1 ] 5754 */ 5755 if (continuous) { 5756 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5757 for (i = 0; i < k - 1; i++) 5758 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5759 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5760 foffset = offset; 5761 } else { 5762 for (i = offset; i < size; i++) perm[i] = i - offset + foffset; 5763 foffset = offset = size; 5764 } 5765 break; 5766 case 2: 5767 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5768 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5769 /* The SEM order is 5770 5771 v_lb, {e_b}, v_rb, 5772 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5773 v_lt, reverse {e_t}, v_rt 5774 */ 5775 if (continuous) { 5776 const PetscInt of = 0; 5777 const PetscInt oeb = of + PetscSqr(k - 1); 5778 const PetscInt oer = oeb + (k - 1); 5779 const PetscInt oet = oer + (k - 1); 5780 const PetscInt oel = oet + (k - 1); 5781 const PetscInt ovlb = oel + (k - 1); 5782 const PetscInt ovrb = ovlb + 1; 5783 const PetscInt ovrt = ovrb + 1; 5784 const PetscInt ovlt = ovrt + 1; 5785 PetscInt o; 5786 5787 /* bottom */ 5788 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5789 for (o = oeb; o < oer; ++o) 5790 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5791 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5792 /* middle */ 5793 for (i = 0; i < k - 1; ++i) { 5794 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5795 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5796 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5797 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5798 } 5799 /* top */ 5800 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5801 for (o = oel - 1; o >= oet; --o) 5802 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5803 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5804 foffset = offset; 5805 } else { 5806 for (i = offset; i < size; i++) perm[i] = i - offset + foffset; 5807 foffset = offset = size; 5808 } 5809 break; 5810 case 3: 5811 /* The original hex closure is 5812 5813 {c, 5814 f_b, f_t, f_f, f_b, f_r, f_l, 5815 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5816 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5817 */ 5818 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5819 /* The SEM order is 5820 Bottom Slice 5821 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5822 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5823 v_blb, {e_bb}, v_brb, 5824 5825 Middle Slice (j) 5826 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5827 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5828 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5829 5830 Top Slice 5831 v_tlf, {e_tf}, v_trf, 5832 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5833 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5834 */ 5835 if (continuous) { 5836 const PetscInt oc = 0; 5837 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5838 const PetscInt oft = ofb + PetscSqr(k - 1); 5839 const PetscInt off = oft + PetscSqr(k - 1); 5840 const PetscInt ofk = off + PetscSqr(k - 1); 5841 const PetscInt ofr = ofk + PetscSqr(k - 1); 5842 const PetscInt ofl = ofr + PetscSqr(k - 1); 5843 const PetscInt oebl = ofl + PetscSqr(k - 1); 5844 const PetscInt oebb = oebl + (k - 1); 5845 const PetscInt oebr = oebb + (k - 1); 5846 const PetscInt oebf = oebr + (k - 1); 5847 const PetscInt oetf = oebf + (k - 1); 5848 const PetscInt oetr = oetf + (k - 1); 5849 const PetscInt oetb = oetr + (k - 1); 5850 const PetscInt oetl = oetb + (k - 1); 5851 const PetscInt oerf = oetl + (k - 1); 5852 const PetscInt oelf = oerf + (k - 1); 5853 const PetscInt oelb = oelf + (k - 1); 5854 const PetscInt oerb = oelb + (k - 1); 5855 const PetscInt ovblf = oerb + (k - 1); 5856 const PetscInt ovblb = ovblf + 1; 5857 const PetscInt ovbrb = ovblb + 1; 5858 const PetscInt ovbrf = ovbrb + 1; 5859 const PetscInt ovtlf = ovbrf + 1; 5860 const PetscInt ovtrf = ovtlf + 1; 5861 const PetscInt ovtrb = ovtrf + 1; 5862 const PetscInt ovtlb = ovtrb + 1; 5863 PetscInt o, n; 5864 5865 /* Bottom Slice */ 5866 /* bottom */ 5867 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5868 for (o = oetf - 1; o >= oebf; --o) 5869 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5870 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5871 /* middle */ 5872 for (i = 0; i < k - 1; ++i) { 5873 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5874 for (n = 0; n < k - 1; ++n) { 5875 o = ofb + n * (k - 1) + i; 5876 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5877 } 5878 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5879 } 5880 /* top */ 5881 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5882 for (o = oebb; o < oebr; ++o) 5883 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5884 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5885 5886 /* Middle Slice */ 5887 for (j = 0; j < k - 1; ++j) { 5888 /* bottom */ 5889 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5890 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5891 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5892 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5893 /* middle */ 5894 for (i = 0; i < k - 1; ++i) { 5895 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5896 for (n = 0; n < k - 1; ++n) 5897 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5898 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5899 } 5900 /* top */ 5901 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5902 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5903 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5904 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5905 } 5906 5907 /* Top Slice */ 5908 /* bottom */ 5909 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5910 for (o = oetf; o < oetr; ++o) 5911 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5912 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5913 /* middle */ 5914 for (i = 0; i < k - 1; ++i) { 5915 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5916 for (n = 0; n < k - 1; ++n) 5917 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5918 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5919 } 5920 /* top */ 5921 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5922 for (o = oetl - 1; o >= oetb; --o) 5923 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5924 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5925 5926 foffset = offset; 5927 } else { 5928 for (i = offset; i < size; i++) perm[i] = i - offset + foffset; 5929 foffset = offset = size; 5930 } 5931 break; 5932 default: 5933 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5934 } 5935 } 5936 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5937 /* Check permutation */ 5938 { 5939 PetscInt *check; 5940 5941 PetscCall(PetscMalloc1(size, &check)); 5942 for (i = 0; i < size; ++i) { 5943 check[i] = -1; 5944 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5945 } 5946 for (i = 0; i < size; ++i) check[perm[i]] = i; 5947 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5948 PetscCall(PetscFree(check)); 5949 } 5950 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5951 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5952 PetscInt *loc_perm; 5953 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5954 for (PetscInt i = 0; i < size; i++) { 5955 loc_perm[i] = perm[i]; 5956 loc_perm[size + i] = size + perm[i]; 5957 } 5958 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5959 } 5960 } 5961 PetscFunctionReturn(PETSC_SUCCESS); 5962 } 5963 5964 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5965 { 5966 PetscDS prob; 5967 PetscInt depth, Nf, h; 5968 DMLabel label; 5969 5970 PetscFunctionBeginHot; 5971 PetscCall(DMGetDS(dm, &prob)); 5972 Nf = prob->Nf; 5973 label = dm->depthLabel; 5974 *dspace = NULL; 5975 if (field < Nf) { 5976 PetscObject disc = prob->disc[field]; 5977 5978 if (disc->classid == PETSCFE_CLASSID) { 5979 PetscDualSpace dsp; 5980 5981 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5982 PetscCall(DMLabelGetNumValues(label, &depth)); 5983 PetscCall(DMLabelGetValue(label, point, &h)); 5984 h = depth - 1 - h; 5985 if (h) { 5986 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5987 } else { 5988 *dspace = dsp; 5989 } 5990 } 5991 } 5992 PetscFunctionReturn(PETSC_SUCCESS); 5993 } 5994 5995 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5996 { 5997 PetscScalar *array; 5998 const PetscScalar *vArray; 5999 const PetscInt *cone, *coneO; 6000 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6001 6002 PetscFunctionBeginHot; 6003 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6004 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6005 PetscCall(DMPlexGetCone(dm, point, &cone)); 6006 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6007 if (!values || !*values) { 6008 if ((point >= pStart) && (point < pEnd)) { 6009 PetscInt dof; 6010 6011 PetscCall(PetscSectionGetDof(section, point, &dof)); 6012 size += dof; 6013 } 6014 for (p = 0; p < numPoints; ++p) { 6015 const PetscInt cp = cone[p]; 6016 PetscInt dof; 6017 6018 if ((cp < pStart) || (cp >= pEnd)) continue; 6019 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6020 size += dof; 6021 } 6022 if (!values) { 6023 if (csize) *csize = size; 6024 PetscFunctionReturn(PETSC_SUCCESS); 6025 } 6026 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6027 } else { 6028 array = *values; 6029 } 6030 size = 0; 6031 PetscCall(VecGetArrayRead(v, &vArray)); 6032 if ((point >= pStart) && (point < pEnd)) { 6033 PetscInt dof, off, d; 6034 const PetscScalar *varr; 6035 6036 PetscCall(PetscSectionGetDof(section, point, &dof)); 6037 PetscCall(PetscSectionGetOffset(section, point, &off)); 6038 varr = &vArray[off]; 6039 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6040 size += dof; 6041 } 6042 for (p = 0; p < numPoints; ++p) { 6043 const PetscInt cp = cone[p]; 6044 PetscInt o = coneO[p]; 6045 PetscInt dof, off, d; 6046 const PetscScalar *varr; 6047 6048 if ((cp < pStart) || (cp >= pEnd)) continue; 6049 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6050 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6051 varr = &vArray[off]; 6052 if (o >= 0) { 6053 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6054 } else { 6055 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6056 } 6057 size += dof; 6058 } 6059 PetscCall(VecRestoreArrayRead(v, &vArray)); 6060 if (!*values) { 6061 if (csize) *csize = size; 6062 *values = array; 6063 } else { 6064 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6065 *csize = size; 6066 } 6067 PetscFunctionReturn(PETSC_SUCCESS); 6068 } 6069 6070 /* Compress out points not in the section */ 6071 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6072 { 6073 const PetscInt np = *numPoints; 6074 PetscInt pStart, pEnd, p, q; 6075 6076 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6077 for (p = 0, q = 0; p < np; ++p) { 6078 const PetscInt r = points[p * 2]; 6079 if ((r >= pStart) && (r < pEnd)) { 6080 points[q * 2] = r; 6081 points[q * 2 + 1] = points[p * 2 + 1]; 6082 ++q; 6083 } 6084 } 6085 *numPoints = q; 6086 return PETSC_SUCCESS; 6087 } 6088 6089 /* Compressed closure does not apply closure permutation */ 6090 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6091 { 6092 const PetscInt *cla = NULL; 6093 PetscInt np, *pts = NULL; 6094 6095 PetscFunctionBeginHot; 6096 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6097 if (!ornt && *clPoints) { 6098 PetscInt dof, off; 6099 6100 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6101 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6102 PetscCall(ISGetIndices(*clPoints, &cla)); 6103 np = dof / 2; 6104 pts = (PetscInt *)&cla[off]; 6105 } else { 6106 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6107 PetscCall(CompressPoints_Private(section, &np, pts)); 6108 } 6109 *numPoints = np; 6110 *points = pts; 6111 *clp = cla; 6112 PetscFunctionReturn(PETSC_SUCCESS); 6113 } 6114 6115 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6116 { 6117 PetscFunctionBeginHot; 6118 if (!*clPoints) { 6119 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6120 } else { 6121 PetscCall(ISRestoreIndices(*clPoints, clp)); 6122 } 6123 *numPoints = 0; 6124 *points = NULL; 6125 *clSec = NULL; 6126 *clPoints = NULL; 6127 *clp = NULL; 6128 PetscFunctionReturn(PETSC_SUCCESS); 6129 } 6130 6131 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6132 { 6133 PetscInt offset = 0, p; 6134 const PetscInt **perms = NULL; 6135 const PetscScalar **flips = NULL; 6136 6137 PetscFunctionBeginHot; 6138 *size = 0; 6139 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6140 for (p = 0; p < numPoints; p++) { 6141 const PetscInt point = points[2 * p]; 6142 const PetscInt *perm = perms ? perms[p] : NULL; 6143 const PetscScalar *flip = flips ? flips[p] : NULL; 6144 PetscInt dof, off, d; 6145 const PetscScalar *varr; 6146 6147 PetscCall(PetscSectionGetDof(section, point, &dof)); 6148 PetscCall(PetscSectionGetOffset(section, point, &off)); 6149 varr = &vArray[off]; 6150 if (clperm) { 6151 if (perm) { 6152 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6153 } else { 6154 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6155 } 6156 if (flip) { 6157 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6158 } 6159 } else { 6160 if (perm) { 6161 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6162 } else { 6163 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6164 } 6165 if (flip) { 6166 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6167 } 6168 } 6169 offset += dof; 6170 } 6171 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6172 *size = offset; 6173 PetscFunctionReturn(PETSC_SUCCESS); 6174 } 6175 6176 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[]) 6177 { 6178 PetscInt offset = 0, f; 6179 6180 PetscFunctionBeginHot; 6181 *size = 0; 6182 for (f = 0; f < numFields; ++f) { 6183 PetscInt p; 6184 const PetscInt **perms = NULL; 6185 const PetscScalar **flips = NULL; 6186 6187 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6188 for (p = 0; p < numPoints; p++) { 6189 const PetscInt point = points[2 * p]; 6190 PetscInt fdof, foff, b; 6191 const PetscScalar *varr; 6192 const PetscInt *perm = perms ? perms[p] : NULL; 6193 const PetscScalar *flip = flips ? flips[p] : NULL; 6194 6195 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6196 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6197 varr = &vArray[foff]; 6198 if (clperm) { 6199 if (perm) { 6200 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6201 } else { 6202 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6203 } 6204 if (flip) { 6205 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6206 } 6207 } else { 6208 if (perm) { 6209 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6210 } else { 6211 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6212 } 6213 if (flip) { 6214 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6215 } 6216 } 6217 offset += fdof; 6218 } 6219 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6220 } 6221 *size = offset; 6222 PetscFunctionReturn(PETSC_SUCCESS); 6223 } 6224 6225 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6226 { 6227 PetscSection clSection; 6228 IS clPoints; 6229 PetscInt *points = NULL; 6230 const PetscInt *clp, *perm = NULL; 6231 PetscInt depth, numFields, numPoints, asize; 6232 6233 PetscFunctionBeginHot; 6234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6235 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6236 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6237 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6238 PetscCall(DMPlexGetDepth(dm, &depth)); 6239 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6240 if (depth == 1 && numFields < 2) { 6241 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6242 PetscFunctionReturn(PETSC_SUCCESS); 6243 } 6244 /* Get points */ 6245 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6246 /* Get sizes */ 6247 asize = 0; 6248 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6249 PetscInt dof; 6250 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6251 asize += dof; 6252 } 6253 if (values) { 6254 const PetscScalar *vArray; 6255 PetscInt size; 6256 6257 if (*values) { 6258 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); 6259 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6260 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6261 PetscCall(VecGetArrayRead(v, &vArray)); 6262 /* Get values */ 6263 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6264 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6265 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6266 /* Cleanup array */ 6267 PetscCall(VecRestoreArrayRead(v, &vArray)); 6268 } 6269 if (csize) *csize = asize; 6270 /* Cleanup points */ 6271 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6272 PetscFunctionReturn(PETSC_SUCCESS); 6273 } 6274 6275 /*@C 6276 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6277 6278 Not collective 6279 6280 Input Parameters: 6281 + dm - The `DM` 6282 . section - The section describing the layout in `v`, or `NULL` to use the default section 6283 . v - The local vector 6284 - point - The point in the `DM` 6285 6286 Input/Output Parameters: 6287 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6288 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6289 if the user provided `NULL`, it is a borrowed array and should not be freed 6290 6291 Level: intermediate 6292 6293 Notes: 6294 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6295 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6296 assembly function, and a user may already have allocated storage for this operation. 6297 6298 A typical use could be 6299 .vb 6300 values = NULL; 6301 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6302 for (cl = 0; cl < clSize; ++cl) { 6303 <Compute on closure> 6304 } 6305 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6306 .ve 6307 or 6308 .vb 6309 PetscMalloc1(clMaxSize, &values); 6310 for (p = pStart; p < pEnd; ++p) { 6311 clSize = clMaxSize; 6312 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6313 for (cl = 0; cl < clSize; ++cl) { 6314 <Compute on closure> 6315 } 6316 } 6317 PetscFree(values); 6318 .ve 6319 6320 Fortran Notes: 6321 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6322 6323 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6324 @*/ 6325 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6326 { 6327 PetscFunctionBeginHot; 6328 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6329 PetscFunctionReturn(PETSC_SUCCESS); 6330 } 6331 6332 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6333 { 6334 DMLabel depthLabel; 6335 PetscSection clSection; 6336 IS clPoints; 6337 PetscScalar *array; 6338 const PetscScalar *vArray; 6339 PetscInt *points = NULL; 6340 const PetscInt *clp, *perm = NULL; 6341 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6342 6343 PetscFunctionBeginHot; 6344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6345 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6346 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6347 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6348 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6349 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6350 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6351 if (mdepth == 1 && numFields < 2) { 6352 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6353 PetscFunctionReturn(PETSC_SUCCESS); 6354 } 6355 /* Get points */ 6356 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6357 for (clsize = 0, p = 0; p < Np; p++) { 6358 PetscInt dof; 6359 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6360 clsize += dof; 6361 } 6362 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6363 /* Filter points */ 6364 for (p = 0; p < numPoints * 2; p += 2) { 6365 PetscInt dep; 6366 6367 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6368 if (dep != depth) continue; 6369 points[Np * 2 + 0] = points[p]; 6370 points[Np * 2 + 1] = points[p + 1]; 6371 ++Np; 6372 } 6373 /* Get array */ 6374 if (!values || !*values) { 6375 PetscInt asize = 0, dof; 6376 6377 for (p = 0; p < Np * 2; p += 2) { 6378 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6379 asize += dof; 6380 } 6381 if (!values) { 6382 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6383 if (csize) *csize = asize; 6384 PetscFunctionReturn(PETSC_SUCCESS); 6385 } 6386 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6387 } else { 6388 array = *values; 6389 } 6390 PetscCall(VecGetArrayRead(v, &vArray)); 6391 /* Get values */ 6392 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6393 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6394 /* Cleanup points */ 6395 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6396 /* Cleanup array */ 6397 PetscCall(VecRestoreArrayRead(v, &vArray)); 6398 if (!*values) { 6399 if (csize) *csize = size; 6400 *values = array; 6401 } else { 6402 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6403 *csize = size; 6404 } 6405 PetscFunctionReturn(PETSC_SUCCESS); 6406 } 6407 6408 /*@C 6409 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6410 6411 Not collective 6412 6413 Input Parameters: 6414 + dm - The `DM` 6415 . section - The section describing the layout in `v`, or `NULL` to use the default section 6416 . v - The local vector 6417 . point - The point in the `DM` 6418 . csize - The number of values in the closure, or `NULL` 6419 - values - The array of values, which is a borrowed array and should not be freed 6420 6421 Level: intermediate 6422 6423 Note: 6424 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6425 6426 Fortran Notes: 6427 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6428 6429 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6430 @*/ 6431 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6432 { 6433 PetscInt size = 0; 6434 6435 PetscFunctionBegin; 6436 /* Should work without recalculating size */ 6437 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6438 *values = NULL; 6439 PetscFunctionReturn(PETSC_SUCCESS); 6440 } 6441 6442 static inline void add(PetscScalar *x, PetscScalar y) 6443 { 6444 *x += y; 6445 } 6446 static inline void insert(PetscScalar *x, PetscScalar y) 6447 { 6448 *x = y; 6449 } 6450 6451 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[]) 6452 { 6453 PetscInt cdof; /* The number of constraints on this point */ 6454 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6455 PetscScalar *a; 6456 PetscInt off, cind = 0, k; 6457 6458 PetscFunctionBegin; 6459 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6460 PetscCall(PetscSectionGetOffset(section, point, &off)); 6461 a = &array[off]; 6462 if (!cdof || setBC) { 6463 if (clperm) { 6464 if (perm) { 6465 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6466 } else { 6467 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6468 } 6469 } else { 6470 if (perm) { 6471 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6472 } else { 6473 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6474 } 6475 } 6476 } else { 6477 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6478 if (clperm) { 6479 if (perm) { 6480 for (k = 0; k < dof; ++k) { 6481 if ((cind < cdof) && (k == cdofs[cind])) { 6482 ++cind; 6483 continue; 6484 } 6485 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6486 } 6487 } else { 6488 for (k = 0; k < dof; ++k) { 6489 if ((cind < cdof) && (k == cdofs[cind])) { 6490 ++cind; 6491 continue; 6492 } 6493 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6494 } 6495 } 6496 } else { 6497 if (perm) { 6498 for (k = 0; k < dof; ++k) { 6499 if ((cind < cdof) && (k == cdofs[cind])) { 6500 ++cind; 6501 continue; 6502 } 6503 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6504 } 6505 } else { 6506 for (k = 0; k < dof; ++k) { 6507 if ((cind < cdof) && (k == cdofs[cind])) { 6508 ++cind; 6509 continue; 6510 } 6511 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6512 } 6513 } 6514 } 6515 } 6516 PetscFunctionReturn(PETSC_SUCCESS); 6517 } 6518 6519 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[]) 6520 { 6521 PetscInt cdof; /* The number of constraints on this point */ 6522 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6523 PetscScalar *a; 6524 PetscInt off, cind = 0, k; 6525 6526 PetscFunctionBegin; 6527 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6528 PetscCall(PetscSectionGetOffset(section, point, &off)); 6529 a = &array[off]; 6530 if (cdof) { 6531 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6532 if (clperm) { 6533 if (perm) { 6534 for (k = 0; k < dof; ++k) { 6535 if ((cind < cdof) && (k == cdofs[cind])) { 6536 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6537 cind++; 6538 } 6539 } 6540 } else { 6541 for (k = 0; k < dof; ++k) { 6542 if ((cind < cdof) && (k == cdofs[cind])) { 6543 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6544 cind++; 6545 } 6546 } 6547 } 6548 } else { 6549 if (perm) { 6550 for (k = 0; k < dof; ++k) { 6551 if ((cind < cdof) && (k == cdofs[cind])) { 6552 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6553 cind++; 6554 } 6555 } 6556 } else { 6557 for (k = 0; k < dof; ++k) { 6558 if ((cind < cdof) && (k == cdofs[cind])) { 6559 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6560 cind++; 6561 } 6562 } 6563 } 6564 } 6565 } 6566 PetscFunctionReturn(PETSC_SUCCESS); 6567 } 6568 6569 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[]) 6570 { 6571 PetscScalar *a; 6572 PetscInt fdof, foff, fcdof, foffset = *offset; 6573 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6574 PetscInt cind = 0, b; 6575 6576 PetscFunctionBegin; 6577 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6578 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6579 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6580 a = &array[foff]; 6581 if (!fcdof || setBC) { 6582 if (clperm) { 6583 if (perm) { 6584 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6585 } else { 6586 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6587 } 6588 } else { 6589 if (perm) { 6590 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6591 } else { 6592 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6593 } 6594 } 6595 } else { 6596 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6597 if (clperm) { 6598 if (perm) { 6599 for (b = 0; b < fdof; b++) { 6600 if ((cind < fcdof) && (b == fcdofs[cind])) { 6601 ++cind; 6602 continue; 6603 } 6604 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6605 } 6606 } else { 6607 for (b = 0; b < fdof; b++) { 6608 if ((cind < fcdof) && (b == fcdofs[cind])) { 6609 ++cind; 6610 continue; 6611 } 6612 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6613 } 6614 } 6615 } else { 6616 if (perm) { 6617 for (b = 0; b < fdof; b++) { 6618 if ((cind < fcdof) && (b == fcdofs[cind])) { 6619 ++cind; 6620 continue; 6621 } 6622 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6623 } 6624 } else { 6625 for (b = 0; b < fdof; b++) { 6626 if ((cind < fcdof) && (b == fcdofs[cind])) { 6627 ++cind; 6628 continue; 6629 } 6630 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6631 } 6632 } 6633 } 6634 } 6635 *offset += fdof; 6636 PetscFunctionReturn(PETSC_SUCCESS); 6637 } 6638 6639 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[]) 6640 { 6641 PetscScalar *a; 6642 PetscInt fdof, foff, fcdof, foffset = *offset; 6643 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6644 PetscInt Nc, cind = 0, ncind = 0, b; 6645 PetscBool ncSet, fcSet; 6646 6647 PetscFunctionBegin; 6648 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6649 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6650 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6651 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6652 a = &array[foff]; 6653 if (fcdof) { 6654 /* We just override fcdof and fcdofs with Ncc and comps */ 6655 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6656 if (clperm) { 6657 if (perm) { 6658 if (comps) { 6659 for (b = 0; b < fdof; b++) { 6660 ncSet = fcSet = PETSC_FALSE; 6661 if (b % Nc == comps[ncind]) { 6662 ncind = (ncind + 1) % Ncc; 6663 ncSet = PETSC_TRUE; 6664 } 6665 if ((cind < fcdof) && (b == fcdofs[cind])) { 6666 ++cind; 6667 fcSet = PETSC_TRUE; 6668 } 6669 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6670 } 6671 } else { 6672 for (b = 0; b < fdof; b++) { 6673 if ((cind < fcdof) && (b == fcdofs[cind])) { 6674 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6675 ++cind; 6676 } 6677 } 6678 } 6679 } else { 6680 if (comps) { 6681 for (b = 0; b < fdof; b++) { 6682 ncSet = fcSet = PETSC_FALSE; 6683 if (b % Nc == comps[ncind]) { 6684 ncind = (ncind + 1) % Ncc; 6685 ncSet = PETSC_TRUE; 6686 } 6687 if ((cind < fcdof) && (b == fcdofs[cind])) { 6688 ++cind; 6689 fcSet = PETSC_TRUE; 6690 } 6691 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6692 } 6693 } else { 6694 for (b = 0; b < fdof; b++) { 6695 if ((cind < fcdof) && (b == fcdofs[cind])) { 6696 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6697 ++cind; 6698 } 6699 } 6700 } 6701 } 6702 } else { 6703 if (perm) { 6704 if (comps) { 6705 for (b = 0; b < fdof; b++) { 6706 ncSet = fcSet = PETSC_FALSE; 6707 if (b % Nc == comps[ncind]) { 6708 ncind = (ncind + 1) % Ncc; 6709 ncSet = PETSC_TRUE; 6710 } 6711 if ((cind < fcdof) && (b == fcdofs[cind])) { 6712 ++cind; 6713 fcSet = PETSC_TRUE; 6714 } 6715 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6716 } 6717 } else { 6718 for (b = 0; b < fdof; b++) { 6719 if ((cind < fcdof) && (b == fcdofs[cind])) { 6720 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6721 ++cind; 6722 } 6723 } 6724 } 6725 } else { 6726 if (comps) { 6727 for (b = 0; b < fdof; b++) { 6728 ncSet = fcSet = PETSC_FALSE; 6729 if (b % Nc == comps[ncind]) { 6730 ncind = (ncind + 1) % Ncc; 6731 ncSet = PETSC_TRUE; 6732 } 6733 if ((cind < fcdof) && (b == fcdofs[cind])) { 6734 ++cind; 6735 fcSet = PETSC_TRUE; 6736 } 6737 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6738 } 6739 } else { 6740 for (b = 0; b < fdof; b++) { 6741 if ((cind < fcdof) && (b == fcdofs[cind])) { 6742 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6743 ++cind; 6744 } 6745 } 6746 } 6747 } 6748 } 6749 } 6750 *offset += fdof; 6751 PetscFunctionReturn(PETSC_SUCCESS); 6752 } 6753 6754 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6755 { 6756 PetscScalar *array; 6757 const PetscInt *cone, *coneO; 6758 PetscInt pStart, pEnd, p, numPoints, off, dof; 6759 6760 PetscFunctionBeginHot; 6761 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6762 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6763 PetscCall(DMPlexGetCone(dm, point, &cone)); 6764 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6765 PetscCall(VecGetArray(v, &array)); 6766 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6767 const PetscInt cp = !p ? point : cone[p - 1]; 6768 const PetscInt o = !p ? 0 : coneO[p - 1]; 6769 6770 if ((cp < pStart) || (cp >= pEnd)) { 6771 dof = 0; 6772 continue; 6773 } 6774 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6775 /* ADD_VALUES */ 6776 { 6777 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6778 PetscScalar *a; 6779 PetscInt cdof, coff, cind = 0, k; 6780 6781 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6782 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6783 a = &array[coff]; 6784 if (!cdof) { 6785 if (o >= 0) { 6786 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6787 } else { 6788 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6789 } 6790 } else { 6791 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6792 if (o >= 0) { 6793 for (k = 0; k < dof; ++k) { 6794 if ((cind < cdof) && (k == cdofs[cind])) { 6795 ++cind; 6796 continue; 6797 } 6798 a[k] += values[off + k]; 6799 } 6800 } else { 6801 for (k = 0; k < dof; ++k) { 6802 if ((cind < cdof) && (k == cdofs[cind])) { 6803 ++cind; 6804 continue; 6805 } 6806 a[k] += values[off + dof - k - 1]; 6807 } 6808 } 6809 } 6810 } 6811 } 6812 PetscCall(VecRestoreArray(v, &array)); 6813 PetscFunctionReturn(PETSC_SUCCESS); 6814 } 6815 6816 /*@C 6817 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6818 6819 Not collective 6820 6821 Input Parameters: 6822 + dm - The `DM` 6823 . section - The section describing the layout in `v`, or `NULL` to use the default section 6824 . v - The local vector 6825 . point - The point in the `DM` 6826 . values - The array of values 6827 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6828 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6829 6830 Level: intermediate 6831 6832 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6833 @*/ 6834 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6835 { 6836 PetscSection clSection; 6837 IS clPoints; 6838 PetscScalar *array; 6839 PetscInt *points = NULL; 6840 const PetscInt *clp, *clperm = NULL; 6841 PetscInt depth, numFields, numPoints, p, clsize; 6842 6843 PetscFunctionBeginHot; 6844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6845 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6846 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6847 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6848 PetscCall(DMPlexGetDepth(dm, &depth)); 6849 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6850 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6851 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6852 PetscFunctionReturn(PETSC_SUCCESS); 6853 } 6854 /* Get points */ 6855 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6856 for (clsize = 0, p = 0; p < numPoints; p++) { 6857 PetscInt dof; 6858 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6859 clsize += dof; 6860 } 6861 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6862 /* Get array */ 6863 PetscCall(VecGetArray(v, &array)); 6864 /* Get values */ 6865 if (numFields > 0) { 6866 PetscInt offset = 0, f; 6867 for (f = 0; f < numFields; ++f) { 6868 const PetscInt **perms = NULL; 6869 const PetscScalar **flips = NULL; 6870 6871 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6872 switch (mode) { 6873 case INSERT_VALUES: 6874 for (p = 0; p < numPoints; p++) { 6875 const PetscInt point = points[2 * p]; 6876 const PetscInt *perm = perms ? perms[p] : NULL; 6877 const PetscScalar *flip = flips ? flips[p] : NULL; 6878 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6879 } 6880 break; 6881 case INSERT_ALL_VALUES: 6882 for (p = 0; p < numPoints; p++) { 6883 const PetscInt point = points[2 * p]; 6884 const PetscInt *perm = perms ? perms[p] : NULL; 6885 const PetscScalar *flip = flips ? flips[p] : NULL; 6886 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6887 } 6888 break; 6889 case INSERT_BC_VALUES: 6890 for (p = 0; p < numPoints; p++) { 6891 const PetscInt point = points[2 * p]; 6892 const PetscInt *perm = perms ? perms[p] : NULL; 6893 const PetscScalar *flip = flips ? flips[p] : NULL; 6894 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6895 } 6896 break; 6897 case ADD_VALUES: 6898 for (p = 0; p < numPoints; p++) { 6899 const PetscInt point = points[2 * p]; 6900 const PetscInt *perm = perms ? perms[p] : NULL; 6901 const PetscScalar *flip = flips ? flips[p] : NULL; 6902 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6903 } 6904 break; 6905 case ADD_ALL_VALUES: 6906 for (p = 0; p < numPoints; p++) { 6907 const PetscInt point = points[2 * p]; 6908 const PetscInt *perm = perms ? perms[p] : NULL; 6909 const PetscScalar *flip = flips ? flips[p] : NULL; 6910 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6911 } 6912 break; 6913 case ADD_BC_VALUES: 6914 for (p = 0; p < numPoints; p++) { 6915 const PetscInt point = points[2 * p]; 6916 const PetscInt *perm = perms ? perms[p] : NULL; 6917 const PetscScalar *flip = flips ? flips[p] : NULL; 6918 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6919 } 6920 break; 6921 default: 6922 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6923 } 6924 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6925 } 6926 } else { 6927 PetscInt dof, off; 6928 const PetscInt **perms = NULL; 6929 const PetscScalar **flips = NULL; 6930 6931 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6932 switch (mode) { 6933 case INSERT_VALUES: 6934 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6935 const PetscInt point = points[2 * p]; 6936 const PetscInt *perm = perms ? perms[p] : NULL; 6937 const PetscScalar *flip = flips ? flips[p] : NULL; 6938 PetscCall(PetscSectionGetDof(section, point, &dof)); 6939 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6940 } 6941 break; 6942 case INSERT_ALL_VALUES: 6943 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6944 const PetscInt point = points[2 * p]; 6945 const PetscInt *perm = perms ? perms[p] : NULL; 6946 const PetscScalar *flip = flips ? flips[p] : NULL; 6947 PetscCall(PetscSectionGetDof(section, point, &dof)); 6948 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6949 } 6950 break; 6951 case INSERT_BC_VALUES: 6952 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6953 const PetscInt point = points[2 * p]; 6954 const PetscInt *perm = perms ? perms[p] : NULL; 6955 const PetscScalar *flip = flips ? flips[p] : NULL; 6956 PetscCall(PetscSectionGetDof(section, point, &dof)); 6957 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6958 } 6959 break; 6960 case ADD_VALUES: 6961 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6962 const PetscInt point = points[2 * p]; 6963 const PetscInt *perm = perms ? perms[p] : NULL; 6964 const PetscScalar *flip = flips ? flips[p] : NULL; 6965 PetscCall(PetscSectionGetDof(section, point, &dof)); 6966 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6967 } 6968 break; 6969 case ADD_ALL_VALUES: 6970 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6971 const PetscInt point = points[2 * p]; 6972 const PetscInt *perm = perms ? perms[p] : NULL; 6973 const PetscScalar *flip = flips ? flips[p] : NULL; 6974 PetscCall(PetscSectionGetDof(section, point, &dof)); 6975 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6976 } 6977 break; 6978 case ADD_BC_VALUES: 6979 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6980 const PetscInt point = points[2 * p]; 6981 const PetscInt *perm = perms ? perms[p] : NULL; 6982 const PetscScalar *flip = flips ? flips[p] : NULL; 6983 PetscCall(PetscSectionGetDof(section, point, &dof)); 6984 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6985 } 6986 break; 6987 default: 6988 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6989 } 6990 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6991 } 6992 /* Cleanup points */ 6993 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6994 /* Cleanup array */ 6995 PetscCall(VecRestoreArray(v, &array)); 6996 PetscFunctionReturn(PETSC_SUCCESS); 6997 } 6998 6999 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7000 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7001 { 7002 PetscFunctionBegin; 7003 *contains = PETSC_TRUE; 7004 if (label) { 7005 PetscInt fdof; 7006 7007 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7008 if (!*contains) { 7009 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7010 *offset += fdof; 7011 PetscFunctionReturn(PETSC_SUCCESS); 7012 } 7013 } 7014 PetscFunctionReturn(PETSC_SUCCESS); 7015 } 7016 7017 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7018 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) 7019 { 7020 PetscSection clSection; 7021 IS clPoints; 7022 PetscScalar *array; 7023 PetscInt *points = NULL; 7024 const PetscInt *clp; 7025 PetscInt numFields, numPoints, p; 7026 PetscInt offset = 0, f; 7027 7028 PetscFunctionBeginHot; 7029 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7030 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7031 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7032 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7033 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7034 /* Get points */ 7035 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7036 /* Get array */ 7037 PetscCall(VecGetArray(v, &array)); 7038 /* Get values */ 7039 for (f = 0; f < numFields; ++f) { 7040 const PetscInt **perms = NULL; 7041 const PetscScalar **flips = NULL; 7042 PetscBool contains; 7043 7044 if (!fieldActive[f]) { 7045 for (p = 0; p < numPoints * 2; p += 2) { 7046 PetscInt fdof; 7047 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7048 offset += fdof; 7049 } 7050 continue; 7051 } 7052 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7053 switch (mode) { 7054 case INSERT_VALUES: 7055 for (p = 0; p < numPoints; p++) { 7056 const PetscInt point = points[2 * p]; 7057 const PetscInt *perm = perms ? perms[p] : NULL; 7058 const PetscScalar *flip = flips ? flips[p] : NULL; 7059 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7060 if (!contains) continue; 7061 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7062 } 7063 break; 7064 case INSERT_ALL_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(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7070 if (!contains) continue; 7071 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7072 } 7073 break; 7074 case INSERT_BC_VALUES: 7075 for (p = 0; p < numPoints; p++) { 7076 const PetscInt point = points[2 * p]; 7077 const PetscInt *perm = perms ? perms[p] : NULL; 7078 const PetscScalar *flip = flips ? flips[p] : NULL; 7079 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7080 if (!contains) continue; 7081 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7082 } 7083 break; 7084 case ADD_VALUES: 7085 for (p = 0; p < numPoints; p++) { 7086 const PetscInt point = points[2 * p]; 7087 const PetscInt *perm = perms ? perms[p] : NULL; 7088 const PetscScalar *flip = flips ? flips[p] : NULL; 7089 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7090 if (!contains) continue; 7091 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7092 } 7093 break; 7094 case ADD_ALL_VALUES: 7095 for (p = 0; p < numPoints; p++) { 7096 const PetscInt point = points[2 * p]; 7097 const PetscInt *perm = perms ? perms[p] : NULL; 7098 const PetscScalar *flip = flips ? flips[p] : NULL; 7099 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7100 if (!contains) continue; 7101 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7102 } 7103 break; 7104 default: 7105 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7106 } 7107 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7108 } 7109 /* Cleanup points */ 7110 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7111 /* Cleanup array */ 7112 PetscCall(VecRestoreArray(v, &array)); 7113 PetscFunctionReturn(PETSC_SUCCESS); 7114 } 7115 7116 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7117 { 7118 PetscMPIInt rank; 7119 PetscInt i, j; 7120 7121 PetscFunctionBegin; 7122 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7123 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7124 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7125 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7126 numCIndices = numCIndices ? numCIndices : numRIndices; 7127 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7128 for (i = 0; i < numRIndices; i++) { 7129 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7130 for (j = 0; j < numCIndices; j++) { 7131 #if defined(PETSC_USE_COMPLEX) 7132 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7133 #else 7134 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7135 #endif 7136 } 7137 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7138 } 7139 PetscFunctionReturn(PETSC_SUCCESS); 7140 } 7141 7142 /* 7143 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7144 7145 Input Parameters: 7146 + section - The section for this data layout 7147 . islocal - Is the section (and thus indices being requested) local or global? 7148 . point - The point contributing dofs with these indices 7149 . off - The global offset of this point 7150 . loff - The local offset of each field 7151 . setBC - The flag determining whether to include indices of boundary values 7152 . perm - A permutation of the dofs on this point, or NULL 7153 - indperm - A permutation of the entire indices array, or NULL 7154 7155 Output Parameter: 7156 . indices - Indices for dofs on this point 7157 7158 Level: developer 7159 7160 Note: The indices could be local or global, depending on the value of 'off'. 7161 */ 7162 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7163 { 7164 PetscInt dof; /* The number of unknowns on this point */ 7165 PetscInt cdof; /* The number of constraints on this point */ 7166 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7167 PetscInt cind = 0, k; 7168 7169 PetscFunctionBegin; 7170 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7171 PetscCall(PetscSectionGetDof(section, point, &dof)); 7172 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7173 if (!cdof || setBC) { 7174 for (k = 0; k < dof; ++k) { 7175 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7176 const PetscInt ind = indperm ? indperm[preind] : preind; 7177 7178 indices[ind] = off + k; 7179 } 7180 } else { 7181 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7182 for (k = 0; k < dof; ++k) { 7183 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7184 const PetscInt ind = indperm ? indperm[preind] : preind; 7185 7186 if ((cind < cdof) && (k == cdofs[cind])) { 7187 /* Insert check for returning constrained indices */ 7188 indices[ind] = -(off + k + 1); 7189 ++cind; 7190 } else { 7191 indices[ind] = off + k - (islocal ? 0 : cind); 7192 } 7193 } 7194 } 7195 *loff += dof; 7196 PetscFunctionReturn(PETSC_SUCCESS); 7197 } 7198 7199 /* 7200 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7201 7202 Input Parameters: 7203 + section - a section (global or local) 7204 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7205 . point - point within section 7206 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7207 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7208 . setBC - identify constrained (boundary condition) points via involution. 7209 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7210 . permsoff - offset 7211 - indperm - index permutation 7212 7213 Output Parameter: 7214 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7215 . indices - array to hold indices (as defined by section) of each dof associated with point 7216 7217 Notes: 7218 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7219 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7220 in the local vector. 7221 7222 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7223 significant). It is invalid to call with a global section and setBC=true. 7224 7225 Developer Note: 7226 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7227 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7228 offset could be obtained from the section instead of passing it explicitly as we do now. 7229 7230 Example: 7231 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7232 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7233 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7234 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. 7235 7236 Level: developer 7237 */ 7238 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[]) 7239 { 7240 PetscInt numFields, foff, f; 7241 7242 PetscFunctionBegin; 7243 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7244 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7245 for (f = 0, foff = 0; f < numFields; ++f) { 7246 PetscInt fdof, cfdof; 7247 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7248 PetscInt cind = 0, b; 7249 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7250 7251 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7252 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7253 if (!cfdof || setBC) { 7254 for (b = 0; b < fdof; ++b) { 7255 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7256 const PetscInt ind = indperm ? indperm[preind] : preind; 7257 7258 indices[ind] = off + foff + b; 7259 } 7260 } else { 7261 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7262 for (b = 0; b < fdof; ++b) { 7263 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7264 const PetscInt ind = indperm ? indperm[preind] : preind; 7265 7266 if ((cind < cfdof) && (b == fcdofs[cind])) { 7267 indices[ind] = -(off + foff + b + 1); 7268 ++cind; 7269 } else { 7270 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7271 } 7272 } 7273 } 7274 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7275 foffs[f] += fdof; 7276 } 7277 PetscFunctionReturn(PETSC_SUCCESS); 7278 } 7279 7280 /* 7281 This version believes the globalSection offsets for each field, rather than just the point offset 7282 7283 . foffs - The offset into 'indices' for each field, since it is segregated by field 7284 7285 Notes: 7286 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7287 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7288 */ 7289 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7290 { 7291 PetscInt numFields, foff, f; 7292 7293 PetscFunctionBegin; 7294 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7295 for (f = 0; f < numFields; ++f) { 7296 PetscInt fdof, cfdof; 7297 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7298 PetscInt cind = 0, b; 7299 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7300 7301 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7302 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7303 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7304 if (!cfdof) { 7305 for (b = 0; b < fdof; ++b) { 7306 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7307 const PetscInt ind = indperm ? indperm[preind] : preind; 7308 7309 indices[ind] = foff + b; 7310 } 7311 } else { 7312 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7313 for (b = 0; b < fdof; ++b) { 7314 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7315 const PetscInt ind = indperm ? indperm[preind] : preind; 7316 7317 if ((cind < cfdof) && (b == fcdofs[cind])) { 7318 indices[ind] = -(foff + b + 1); 7319 ++cind; 7320 } else { 7321 indices[ind] = foff + b - cind; 7322 } 7323 } 7324 } 7325 foffs[f] += fdof; 7326 } 7327 PetscFunctionReturn(PETSC_SUCCESS); 7328 } 7329 7330 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) 7331 { 7332 Mat cMat; 7333 PetscSection aSec, cSec; 7334 IS aIS; 7335 PetscInt aStart = -1, aEnd = -1; 7336 const PetscInt *anchors; 7337 PetscInt numFields, f, p, q, newP = 0; 7338 PetscInt newNumPoints = 0, newNumIndices = 0; 7339 PetscInt *newPoints, *indices, *newIndices; 7340 PetscInt maxAnchor, maxDof; 7341 PetscInt newOffsets[32]; 7342 PetscInt *pointMatOffsets[32]; 7343 PetscInt *newPointOffsets[32]; 7344 PetscScalar *pointMat[32]; 7345 PetscScalar *newValues = NULL, *tmpValues; 7346 PetscBool anyConstrained = PETSC_FALSE; 7347 7348 PetscFunctionBegin; 7349 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7350 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7351 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7352 7353 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7354 /* if there are point-to-point constraints */ 7355 if (aSec) { 7356 PetscCall(PetscArrayzero(newOffsets, 32)); 7357 PetscCall(ISGetIndices(aIS, &anchors)); 7358 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7359 /* figure out how many points are going to be in the new element matrix 7360 * (we allow double counting, because it's all just going to be summed 7361 * into the global matrix anyway) */ 7362 for (p = 0; p < 2 * numPoints; p += 2) { 7363 PetscInt b = points[p]; 7364 PetscInt bDof = 0, bSecDof; 7365 7366 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7367 if (!bSecDof) continue; 7368 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7369 if (bDof) { 7370 /* this point is constrained */ 7371 /* it is going to be replaced by its anchors */ 7372 PetscInt bOff, q; 7373 7374 anyConstrained = PETSC_TRUE; 7375 newNumPoints += bDof; 7376 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7377 for (q = 0; q < bDof; q++) { 7378 PetscInt a = anchors[bOff + q]; 7379 PetscInt aDof; 7380 7381 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7382 newNumIndices += aDof; 7383 for (f = 0; f < numFields; ++f) { 7384 PetscInt fDof; 7385 7386 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7387 newOffsets[f + 1] += fDof; 7388 } 7389 } 7390 } else { 7391 /* this point is not constrained */ 7392 newNumPoints++; 7393 newNumIndices += bSecDof; 7394 for (f = 0; f < numFields; ++f) { 7395 PetscInt fDof; 7396 7397 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7398 newOffsets[f + 1] += fDof; 7399 } 7400 } 7401 } 7402 } 7403 if (!anyConstrained) { 7404 if (outNumPoints) *outNumPoints = 0; 7405 if (outNumIndices) *outNumIndices = 0; 7406 if (outPoints) *outPoints = NULL; 7407 if (outValues) *outValues = NULL; 7408 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7409 PetscFunctionReturn(PETSC_SUCCESS); 7410 } 7411 7412 if (outNumPoints) *outNumPoints = newNumPoints; 7413 if (outNumIndices) *outNumIndices = newNumIndices; 7414 7415 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7416 7417 if (!outPoints && !outValues) { 7418 if (offsets) { 7419 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7420 } 7421 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7422 PetscFunctionReturn(PETSC_SUCCESS); 7423 } 7424 7425 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7426 7427 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7428 7429 /* workspaces */ 7430 if (numFields) { 7431 for (f = 0; f < numFields; f++) { 7432 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7433 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7434 } 7435 } else { 7436 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7437 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7438 } 7439 7440 /* get workspaces for the point-to-point matrices */ 7441 if (numFields) { 7442 PetscInt totalOffset, totalMatOffset; 7443 7444 for (p = 0; p < numPoints; p++) { 7445 PetscInt b = points[2 * p]; 7446 PetscInt bDof = 0, bSecDof; 7447 7448 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7449 if (!bSecDof) { 7450 for (f = 0; f < numFields; f++) { 7451 newPointOffsets[f][p + 1] = 0; 7452 pointMatOffsets[f][p + 1] = 0; 7453 } 7454 continue; 7455 } 7456 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7457 if (bDof) { 7458 for (f = 0; f < numFields; f++) { 7459 PetscInt fDof, q, bOff, allFDof = 0; 7460 7461 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7462 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7463 for (q = 0; q < bDof; q++) { 7464 PetscInt a = anchors[bOff + q]; 7465 PetscInt aFDof; 7466 7467 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7468 allFDof += aFDof; 7469 } 7470 newPointOffsets[f][p + 1] = allFDof; 7471 pointMatOffsets[f][p + 1] = fDof * allFDof; 7472 } 7473 } else { 7474 for (f = 0; f < numFields; f++) { 7475 PetscInt fDof; 7476 7477 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7478 newPointOffsets[f][p + 1] = fDof; 7479 pointMatOffsets[f][p + 1] = 0; 7480 } 7481 } 7482 } 7483 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7484 newPointOffsets[f][0] = totalOffset; 7485 pointMatOffsets[f][0] = totalMatOffset; 7486 for (p = 0; p < numPoints; p++) { 7487 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7488 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7489 } 7490 totalOffset = newPointOffsets[f][numPoints]; 7491 totalMatOffset = pointMatOffsets[f][numPoints]; 7492 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7493 } 7494 } else { 7495 for (p = 0; p < numPoints; p++) { 7496 PetscInt b = points[2 * p]; 7497 PetscInt bDof = 0, bSecDof; 7498 7499 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7500 if (!bSecDof) { 7501 newPointOffsets[0][p + 1] = 0; 7502 pointMatOffsets[0][p + 1] = 0; 7503 continue; 7504 } 7505 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7506 if (bDof) { 7507 PetscInt bOff, q, allDof = 0; 7508 7509 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7510 for (q = 0; q < bDof; q++) { 7511 PetscInt a = anchors[bOff + q], aDof; 7512 7513 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7514 allDof += aDof; 7515 } 7516 newPointOffsets[0][p + 1] = allDof; 7517 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7518 } else { 7519 newPointOffsets[0][p + 1] = bSecDof; 7520 pointMatOffsets[0][p + 1] = 0; 7521 } 7522 } 7523 newPointOffsets[0][0] = 0; 7524 pointMatOffsets[0][0] = 0; 7525 for (p = 0; p < numPoints; p++) { 7526 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7527 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7528 } 7529 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7530 } 7531 7532 /* output arrays */ 7533 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7534 7535 /* get the point-to-point matrices; construct newPoints */ 7536 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7537 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7538 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7539 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7540 if (numFields) { 7541 for (p = 0, newP = 0; p < numPoints; p++) { 7542 PetscInt b = points[2 * p]; 7543 PetscInt o = points[2 * p + 1]; 7544 PetscInt bDof = 0, bSecDof; 7545 7546 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7547 if (!bSecDof) continue; 7548 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7549 if (bDof) { 7550 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7551 7552 fStart[0] = 0; 7553 fEnd[0] = 0; 7554 for (f = 0; f < numFields; f++) { 7555 PetscInt fDof; 7556 7557 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7558 fStart[f + 1] = fStart[f] + fDof; 7559 fEnd[f + 1] = fStart[f + 1]; 7560 } 7561 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7562 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7563 7564 fAnchorStart[0] = 0; 7565 fAnchorEnd[0] = 0; 7566 for (f = 0; f < numFields; f++) { 7567 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7568 7569 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7570 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7571 } 7572 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7573 for (q = 0; q < bDof; q++) { 7574 PetscInt a = anchors[bOff + q], aOff; 7575 7576 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7577 newPoints[2 * (newP + q)] = a; 7578 newPoints[2 * (newP + q) + 1] = 0; 7579 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7580 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7581 } 7582 newP += bDof; 7583 7584 if (outValues) { 7585 /* get the point-to-point submatrix */ 7586 for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p])); 7587 } 7588 } else { 7589 newPoints[2 * newP] = b; 7590 newPoints[2 * newP + 1] = o; 7591 newP++; 7592 } 7593 } 7594 } else { 7595 for (p = 0; p < numPoints; p++) { 7596 PetscInt b = points[2 * p]; 7597 PetscInt o = points[2 * p + 1]; 7598 PetscInt bDof = 0, bSecDof; 7599 7600 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7601 if (!bSecDof) continue; 7602 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7603 if (bDof) { 7604 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7605 7606 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7607 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7608 7609 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7610 for (q = 0; q < bDof; q++) { 7611 PetscInt a = anchors[bOff + q], aOff; 7612 7613 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7614 7615 newPoints[2 * (newP + q)] = a; 7616 newPoints[2 * (newP + q) + 1] = 0; 7617 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7618 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7619 } 7620 newP += bDof; 7621 7622 /* get the point-to-point submatrix */ 7623 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7624 } else { 7625 newPoints[2 * newP] = b; 7626 newPoints[2 * newP + 1] = o; 7627 newP++; 7628 } 7629 } 7630 } 7631 7632 if (outValues) { 7633 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7634 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7635 /* multiply constraints on the right */ 7636 if (numFields) { 7637 for (f = 0; f < numFields; f++) { 7638 PetscInt oldOff = offsets[f]; 7639 7640 for (p = 0; p < numPoints; p++) { 7641 PetscInt cStart = newPointOffsets[f][p]; 7642 PetscInt b = points[2 * p]; 7643 PetscInt c, r, k; 7644 PetscInt dof; 7645 7646 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7647 if (!dof) continue; 7648 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7649 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7650 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7651 7652 for (r = 0; r < numIndices; r++) { 7653 for (c = 0; c < nCols; c++) { 7654 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7655 } 7656 } 7657 } else { 7658 /* copy this column as is */ 7659 for (r = 0; r < numIndices; r++) { 7660 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7661 } 7662 } 7663 oldOff += dof; 7664 } 7665 } 7666 } else { 7667 PetscInt oldOff = 0; 7668 for (p = 0; p < numPoints; p++) { 7669 PetscInt cStart = newPointOffsets[0][p]; 7670 PetscInt b = points[2 * p]; 7671 PetscInt c, r, k; 7672 PetscInt dof; 7673 7674 PetscCall(PetscSectionGetDof(section, b, &dof)); 7675 if (!dof) continue; 7676 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7677 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7678 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7679 7680 for (r = 0; r < numIndices; r++) { 7681 for (c = 0; c < nCols; c++) { 7682 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7683 } 7684 } 7685 } else { 7686 /* copy this column as is */ 7687 for (r = 0; r < numIndices; r++) { 7688 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7689 } 7690 } 7691 oldOff += dof; 7692 } 7693 } 7694 7695 if (multiplyLeft) { 7696 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7697 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7698 /* multiply constraints transpose on the left */ 7699 if (numFields) { 7700 for (f = 0; f < numFields; f++) { 7701 PetscInt oldOff = offsets[f]; 7702 7703 for (p = 0; p < numPoints; p++) { 7704 PetscInt rStart = newPointOffsets[f][p]; 7705 PetscInt b = points[2 * p]; 7706 PetscInt c, r, k; 7707 PetscInt dof; 7708 7709 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7710 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7711 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7712 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7713 7714 for (r = 0; r < nRows; r++) { 7715 for (c = 0; c < newNumIndices; c++) { 7716 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7717 } 7718 } 7719 } else { 7720 /* copy this row as is */ 7721 for (r = 0; r < dof; r++) { 7722 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7723 } 7724 } 7725 oldOff += dof; 7726 } 7727 } 7728 } else { 7729 PetscInt oldOff = 0; 7730 7731 for (p = 0; p < numPoints; p++) { 7732 PetscInt rStart = newPointOffsets[0][p]; 7733 PetscInt b = points[2 * p]; 7734 PetscInt c, r, k; 7735 PetscInt dof; 7736 7737 PetscCall(PetscSectionGetDof(section, b, &dof)); 7738 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7739 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7740 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7741 7742 for (r = 0; r < nRows; r++) { 7743 for (c = 0; c < newNumIndices; c++) { 7744 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7745 } 7746 } 7747 } else { 7748 /* copy this row as is */ 7749 for (r = 0; r < dof; r++) { 7750 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7751 } 7752 } 7753 oldOff += dof; 7754 } 7755 } 7756 7757 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7758 } else { 7759 newValues = tmpValues; 7760 } 7761 } 7762 7763 /* clean up */ 7764 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7765 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7766 7767 if (numFields) { 7768 for (f = 0; f < numFields; f++) { 7769 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7770 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7771 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7772 } 7773 } else { 7774 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7775 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7776 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7777 } 7778 PetscCall(ISRestoreIndices(aIS, &anchors)); 7779 7780 /* output */ 7781 if (outPoints) { 7782 *outPoints = newPoints; 7783 } else { 7784 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7785 } 7786 if (outValues) *outValues = newValues; 7787 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7788 PetscFunctionReturn(PETSC_SUCCESS); 7789 } 7790 7791 /*@C 7792 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7793 7794 Not collective 7795 7796 Input Parameters: 7797 + dm - The `DM` 7798 . section - The `PetscSection` describing the points (a local section) 7799 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7800 . point - The point defining the closure 7801 - useClPerm - Use the closure point permutation if available 7802 7803 Output Parameters: 7804 + numIndices - The number of dof indices in the closure of point with the input sections 7805 . indices - The dof indices 7806 . outOffsets - Array to write the field offsets into, or `NULL` 7807 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7808 7809 Level: advanced 7810 7811 Notes: 7812 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7813 7814 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7815 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7816 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7817 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7818 indices (with the above semantics) are implied. 7819 7820 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7821 `PetscSection`, `DMGetGlobalSection()` 7822 @*/ 7823 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7824 { 7825 /* Closure ordering */ 7826 PetscSection clSection; 7827 IS clPoints; 7828 const PetscInt *clp; 7829 PetscInt *points; 7830 const PetscInt *clperm = NULL; 7831 /* Dof permutation and sign flips */ 7832 const PetscInt **perms[32] = {NULL}; 7833 const PetscScalar **flips[32] = {NULL}; 7834 PetscScalar *valCopy = NULL; 7835 /* Hanging node constraints */ 7836 PetscInt *pointsC = NULL; 7837 PetscScalar *valuesC = NULL; 7838 PetscInt NclC, NiC; 7839 7840 PetscInt *idx; 7841 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7842 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7843 7844 PetscFunctionBeginHot; 7845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7846 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7847 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7848 if (numIndices) PetscAssertPointer(numIndices, 6); 7849 if (indices) PetscAssertPointer(indices, 7); 7850 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7851 if (values) PetscAssertPointer(values, 9); 7852 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7853 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7854 PetscCall(PetscArrayzero(offsets, 32)); 7855 /* 1) Get points in closure */ 7856 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7857 if (useClPerm) { 7858 PetscInt depth, clsize; 7859 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7860 for (clsize = 0, p = 0; p < Ncl; p++) { 7861 PetscInt dof; 7862 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7863 clsize += dof; 7864 } 7865 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7866 } 7867 /* 2) Get number of indices on these points and field offsets from section */ 7868 for (p = 0; p < Ncl * 2; p += 2) { 7869 PetscInt dof, fdof; 7870 7871 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7872 for (f = 0; f < Nf; ++f) { 7873 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7874 offsets[f + 1] += fdof; 7875 } 7876 Ni += dof; 7877 } 7878 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7879 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7880 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7881 for (f = 0; f < PetscMax(1, Nf); ++f) { 7882 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7883 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7884 /* may need to apply sign changes to the element matrix */ 7885 if (values && flips[f]) { 7886 PetscInt foffset = offsets[f]; 7887 7888 for (p = 0; p < Ncl; ++p) { 7889 PetscInt pnt = points[2 * p], fdof; 7890 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7891 7892 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7893 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7894 if (flip) { 7895 PetscInt i, j, k; 7896 7897 if (!valCopy) { 7898 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7899 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7900 *values = valCopy; 7901 } 7902 for (i = 0; i < fdof; ++i) { 7903 PetscScalar fval = flip[i]; 7904 7905 for (k = 0; k < Ni; ++k) { 7906 valCopy[Ni * (foffset + i) + k] *= fval; 7907 valCopy[Ni * k + (foffset + i)] *= fval; 7908 } 7909 } 7910 } 7911 foffset += fdof; 7912 } 7913 } 7914 } 7915 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7916 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7917 if (NclC) { 7918 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7919 for (f = 0; f < PetscMax(1, Nf); ++f) { 7920 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7921 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7922 } 7923 for (f = 0; f < PetscMax(1, Nf); ++f) { 7924 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7925 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7926 } 7927 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7928 Ncl = NclC; 7929 Ni = NiC; 7930 points = pointsC; 7931 if (values) *values = valuesC; 7932 } 7933 /* 5) Calculate indices */ 7934 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7935 if (Nf) { 7936 PetscInt idxOff; 7937 PetscBool useFieldOffsets; 7938 7939 if (outOffsets) { 7940 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7941 } 7942 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7943 if (useFieldOffsets) { 7944 for (p = 0; p < Ncl; ++p) { 7945 const PetscInt pnt = points[p * 2]; 7946 7947 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7948 } 7949 } else { 7950 for (p = 0; p < Ncl; ++p) { 7951 const PetscInt pnt = points[p * 2]; 7952 7953 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7954 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7955 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7956 * global section. */ 7957 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7958 } 7959 } 7960 } else { 7961 PetscInt off = 0, idxOff; 7962 7963 for (p = 0; p < Ncl; ++p) { 7964 const PetscInt pnt = points[p * 2]; 7965 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7966 7967 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7968 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7969 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7970 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7971 } 7972 } 7973 /* 6) Cleanup */ 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 if (NclC) { 7979 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7980 } else { 7981 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7982 } 7983 7984 if (numIndices) *numIndices = Ni; 7985 if (indices) *indices = idx; 7986 PetscFunctionReturn(PETSC_SUCCESS); 7987 } 7988 7989 /*@C 7990 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7991 7992 Not collective 7993 7994 Input Parameters: 7995 + dm - The `DM` 7996 . section - The `PetscSection` describing the points (a local section) 7997 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7998 . point - The point defining the closure 7999 - useClPerm - Use the closure point permutation if available 8000 8001 Output Parameters: 8002 + numIndices - The number of dof indices in the closure of point with the input sections 8003 . indices - The dof indices 8004 . outOffsets - Array to write the field offsets into, or `NULL` 8005 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8006 8007 Level: advanced 8008 8009 Notes: 8010 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8011 8012 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8013 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8014 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8015 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8016 indices (with the above semantics) are implied. 8017 8018 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8019 @*/ 8020 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8021 { 8022 PetscFunctionBegin; 8023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8024 PetscAssertPointer(indices, 7); 8025 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8026 PetscFunctionReturn(PETSC_SUCCESS); 8027 } 8028 8029 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8030 { 8031 DM_Plex *mesh = (DM_Plex *)dm->data; 8032 PetscInt *indices; 8033 PetscInt numIndices; 8034 const PetscScalar *valuesOrig = values; 8035 PetscErrorCode ierr; 8036 8037 PetscFunctionBegin; 8038 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8039 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8040 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8041 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8042 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8043 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8044 8045 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8046 8047 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8048 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8049 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8050 if (ierr) { 8051 PetscMPIInt rank; 8052 8053 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8054 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8055 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8056 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8057 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8058 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8059 } 8060 if (mesh->printFEM > 1) { 8061 PetscInt i; 8062 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8063 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8064 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8065 } 8066 8067 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8068 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8069 PetscFunctionReturn(PETSC_SUCCESS); 8070 } 8071 8072 /*@C 8073 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8074 8075 Not collective 8076 8077 Input Parameters: 8078 + dm - The `DM` 8079 . section - The section describing the layout in `v`, or `NULL` to use the default section 8080 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8081 . A - The matrix 8082 . point - The point in the `DM` 8083 . values - The array of values 8084 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8085 8086 Level: intermediate 8087 8088 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8089 @*/ 8090 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8091 { 8092 PetscFunctionBegin; 8093 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8094 PetscFunctionReturn(PETSC_SUCCESS); 8095 } 8096 8097 /*@C 8098 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8099 8100 Not collective 8101 8102 Input Parameters: 8103 + dmRow - The `DM` for the row fields 8104 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8105 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8106 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8107 . dmCol - The `DM` for the column fields 8108 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8109 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8110 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8111 . A - The matrix 8112 . point - The point in the `DM` 8113 . values - The array of values 8114 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8115 8116 Level: intermediate 8117 8118 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8119 @*/ 8120 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) 8121 { 8122 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8123 PetscInt *indicesRow, *indicesCol; 8124 PetscInt numIndicesRow, numIndicesCol; 8125 const PetscScalar *valuesOrig = values; 8126 PetscErrorCode ierr; 8127 8128 PetscFunctionBegin; 8129 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8130 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8131 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8132 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8133 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8134 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8135 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8136 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8137 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8138 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8139 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8140 8141 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8142 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8143 8144 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8145 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8146 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8147 if (ierr) { 8148 PetscMPIInt rank; 8149 8150 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8151 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8152 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8153 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8154 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8155 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8156 } 8157 8158 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8159 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8160 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8161 PetscFunctionReturn(PETSC_SUCCESS); 8162 } 8163 8164 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8165 { 8166 DM_Plex *mesh = (DM_Plex *)dmf->data; 8167 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8168 PetscInt *cpoints = NULL; 8169 PetscInt *findices, *cindices; 8170 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8171 PetscInt foffsets[32], coffsets[32]; 8172 DMPolytopeType ct; 8173 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8174 PetscErrorCode ierr; 8175 8176 PetscFunctionBegin; 8177 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8178 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8179 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8180 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8181 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8182 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8183 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8184 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8185 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8186 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8187 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8188 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8189 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8190 PetscCall(PetscArrayzero(foffsets, 32)); 8191 PetscCall(PetscArrayzero(coffsets, 32)); 8192 /* Column indices */ 8193 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8194 maxFPoints = numCPoints; 8195 /* Compress out points not in the section */ 8196 /* TODO: Squeeze out points with 0 dof as well */ 8197 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8198 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8199 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8200 cpoints[q * 2] = cpoints[p]; 8201 cpoints[q * 2 + 1] = cpoints[p + 1]; 8202 ++q; 8203 } 8204 } 8205 numCPoints = q; 8206 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8207 PetscInt fdof; 8208 8209 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8210 if (!dof) continue; 8211 for (f = 0; f < numFields; ++f) { 8212 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8213 coffsets[f + 1] += fdof; 8214 } 8215 numCIndices += dof; 8216 } 8217 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8218 /* Row indices */ 8219 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8220 { 8221 DMPlexTransform tr; 8222 DMPolytopeType *rct; 8223 PetscInt *rsize, *rcone, *rornt, Nt; 8224 8225 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8226 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8227 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8228 numSubcells = rsize[Nt - 1]; 8229 PetscCall(DMPlexTransformDestroy(&tr)); 8230 } 8231 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8232 for (r = 0, q = 0; r < numSubcells; ++r) { 8233 /* TODO Map from coarse to fine cells */ 8234 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8235 /* Compress out points not in the section */ 8236 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8237 for (p = 0; p < numFPoints * 2; p += 2) { 8238 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8239 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8240 if (!dof) continue; 8241 for (s = 0; s < q; ++s) 8242 if (fpoints[p] == ftotpoints[s * 2]) break; 8243 if (s < q) continue; 8244 ftotpoints[q * 2] = fpoints[p]; 8245 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8246 ++q; 8247 } 8248 } 8249 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8250 } 8251 numFPoints = q; 8252 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8253 PetscInt fdof; 8254 8255 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8256 if (!dof) continue; 8257 for (f = 0; f < numFields; ++f) { 8258 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8259 foffsets[f + 1] += fdof; 8260 } 8261 numFIndices += dof; 8262 } 8263 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8264 8265 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8266 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8267 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8268 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8269 if (numFields) { 8270 const PetscInt **permsF[32] = {NULL}; 8271 const PetscInt **permsC[32] = {NULL}; 8272 8273 for (f = 0; f < numFields; f++) { 8274 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8275 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8276 } 8277 for (p = 0; p < numFPoints; p++) { 8278 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8279 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8280 } 8281 for (p = 0; p < numCPoints; p++) { 8282 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8283 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8284 } 8285 for (f = 0; f < numFields; f++) { 8286 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8287 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8288 } 8289 } else { 8290 const PetscInt **permsF = NULL; 8291 const PetscInt **permsC = NULL; 8292 8293 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8294 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8295 for (p = 0, off = 0; p < numFPoints; p++) { 8296 const PetscInt *perm = permsF ? permsF[p] : NULL; 8297 8298 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8299 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8300 } 8301 for (p = 0, off = 0; p < numCPoints; p++) { 8302 const PetscInt *perm = permsC ? permsC[p] : NULL; 8303 8304 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8305 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8306 } 8307 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8308 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8309 } 8310 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8311 /* TODO: flips */ 8312 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8313 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8314 if (ierr) { 8315 PetscMPIInt rank; 8316 8317 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8318 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8319 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8320 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8321 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8322 } 8323 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8324 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8325 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8326 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8327 PetscFunctionReturn(PETSC_SUCCESS); 8328 } 8329 8330 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8331 { 8332 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8333 PetscInt *cpoints = NULL; 8334 PetscInt foffsets[32], coffsets[32]; 8335 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8336 DMPolytopeType ct; 8337 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8338 8339 PetscFunctionBegin; 8340 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8341 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8342 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8343 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8344 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8345 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8346 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8347 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8348 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8349 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8350 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8351 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8352 PetscCall(PetscArrayzero(foffsets, 32)); 8353 PetscCall(PetscArrayzero(coffsets, 32)); 8354 /* Column indices */ 8355 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8356 maxFPoints = numCPoints; 8357 /* Compress out points not in the section */ 8358 /* TODO: Squeeze out points with 0 dof as well */ 8359 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8360 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8361 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8362 cpoints[q * 2] = cpoints[p]; 8363 cpoints[q * 2 + 1] = cpoints[p + 1]; 8364 ++q; 8365 } 8366 } 8367 numCPoints = q; 8368 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8369 PetscInt fdof; 8370 8371 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8372 if (!dof) continue; 8373 for (f = 0; f < numFields; ++f) { 8374 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8375 coffsets[f + 1] += fdof; 8376 } 8377 numCIndices += dof; 8378 } 8379 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8380 /* Row indices */ 8381 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8382 { 8383 DMPlexTransform tr; 8384 DMPolytopeType *rct; 8385 PetscInt *rsize, *rcone, *rornt, Nt; 8386 8387 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8388 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8389 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8390 numSubcells = rsize[Nt - 1]; 8391 PetscCall(DMPlexTransformDestroy(&tr)); 8392 } 8393 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8394 for (r = 0, q = 0; r < numSubcells; ++r) { 8395 /* TODO Map from coarse to fine cells */ 8396 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8397 /* Compress out points not in the section */ 8398 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8399 for (p = 0; p < numFPoints * 2; p += 2) { 8400 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8401 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8402 if (!dof) continue; 8403 for (s = 0; s < q; ++s) 8404 if (fpoints[p] == ftotpoints[s * 2]) break; 8405 if (s < q) continue; 8406 ftotpoints[q * 2] = fpoints[p]; 8407 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8408 ++q; 8409 } 8410 } 8411 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8412 } 8413 numFPoints = q; 8414 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8415 PetscInt fdof; 8416 8417 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8418 if (!dof) continue; 8419 for (f = 0; f < numFields; ++f) { 8420 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8421 foffsets[f + 1] += fdof; 8422 } 8423 numFIndices += dof; 8424 } 8425 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8426 8427 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8428 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8429 if (numFields) { 8430 const PetscInt **permsF[32] = {NULL}; 8431 const PetscInt **permsC[32] = {NULL}; 8432 8433 for (f = 0; f < numFields; f++) { 8434 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8435 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8436 } 8437 for (p = 0; p < numFPoints; p++) { 8438 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8439 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8440 } 8441 for (p = 0; p < numCPoints; p++) { 8442 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8443 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8444 } 8445 for (f = 0; f < numFields; f++) { 8446 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8447 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8448 } 8449 } else { 8450 const PetscInt **permsF = NULL; 8451 const PetscInt **permsC = NULL; 8452 8453 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8454 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8455 for (p = 0, off = 0; p < numFPoints; p++) { 8456 const PetscInt *perm = permsF ? permsF[p] : NULL; 8457 8458 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8459 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8460 } 8461 for (p = 0, off = 0; p < numCPoints; p++) { 8462 const PetscInt *perm = permsC ? permsC[p] : NULL; 8463 8464 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8465 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8466 } 8467 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8468 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8469 } 8470 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8471 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8472 PetscFunctionReturn(PETSC_SUCCESS); 8473 } 8474 8475 /*@C 8476 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8477 8478 Input Parameter: 8479 . dm - The `DMPLEX` object 8480 8481 Output Parameter: 8482 . cellHeight - The height of a cell 8483 8484 Level: developer 8485 8486 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8487 @*/ 8488 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8489 { 8490 DM_Plex *mesh = (DM_Plex *)dm->data; 8491 8492 PetscFunctionBegin; 8493 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8494 PetscAssertPointer(cellHeight, 2); 8495 *cellHeight = mesh->vtkCellHeight; 8496 PetscFunctionReturn(PETSC_SUCCESS); 8497 } 8498 8499 /*@C 8500 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8501 8502 Input Parameters: 8503 + dm - The `DMPLEX` object 8504 - cellHeight - The height of a cell 8505 8506 Level: developer 8507 8508 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8509 @*/ 8510 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8511 { 8512 DM_Plex *mesh = (DM_Plex *)dm->data; 8513 8514 PetscFunctionBegin; 8515 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8516 mesh->vtkCellHeight = cellHeight; 8517 PetscFunctionReturn(PETSC_SUCCESS); 8518 } 8519 8520 /*@ 8521 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8522 8523 Input Parameters: 8524 + dm - The `DMPLEX` object 8525 - ct - The `DMPolytopeType` of the cell 8526 8527 Output Parameters: 8528 + start - The first cell of this type, or `NULL` 8529 - end - The upper bound on this celltype, or `NULL` 8530 8531 Level: advanced 8532 8533 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8534 @*/ 8535 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8536 { 8537 DM_Plex *mesh = (DM_Plex *)dm->data; 8538 DMLabel label; 8539 PetscInt pStart, pEnd; 8540 8541 PetscFunctionBegin; 8542 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8543 if (start) { 8544 PetscAssertPointer(start, 3); 8545 *start = 0; 8546 } 8547 if (end) { 8548 PetscAssertPointer(end, 4); 8549 *end = 0; 8550 } 8551 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8552 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8553 if (mesh->tr) { 8554 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8555 } else { 8556 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8557 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8558 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8559 } 8560 PetscFunctionReturn(PETSC_SUCCESS); 8561 } 8562 8563 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8564 { 8565 PetscSection section, globalSection; 8566 PetscInt *numbers, p; 8567 8568 PetscFunctionBegin; 8569 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8570 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8571 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8572 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8573 PetscCall(PetscSectionSetUp(section)); 8574 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8575 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8576 for (p = pStart; p < pEnd; ++p) { 8577 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8578 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8579 else numbers[p - pStart] += shift; 8580 } 8581 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8582 if (globalSize) { 8583 PetscLayout layout; 8584 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8585 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8586 PetscCall(PetscLayoutDestroy(&layout)); 8587 } 8588 PetscCall(PetscSectionDestroy(§ion)); 8589 PetscCall(PetscSectionDestroy(&globalSection)); 8590 PetscFunctionReturn(PETSC_SUCCESS); 8591 } 8592 8593 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8594 { 8595 PetscInt cellHeight, cStart, cEnd; 8596 8597 PetscFunctionBegin; 8598 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8599 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8600 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8601 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8602 PetscFunctionReturn(PETSC_SUCCESS); 8603 } 8604 8605 /*@ 8606 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8607 8608 Input Parameter: 8609 . dm - The `DMPLEX` object 8610 8611 Output Parameter: 8612 . globalCellNumbers - Global cell numbers for all cells on this process 8613 8614 Level: developer 8615 8616 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8617 @*/ 8618 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8619 { 8620 DM_Plex *mesh = (DM_Plex *)dm->data; 8621 8622 PetscFunctionBegin; 8623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8624 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8625 *globalCellNumbers = mesh->globalCellNumbers; 8626 PetscFunctionReturn(PETSC_SUCCESS); 8627 } 8628 8629 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8630 { 8631 PetscInt vStart, vEnd; 8632 8633 PetscFunctionBegin; 8634 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8635 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8636 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8637 PetscFunctionReturn(PETSC_SUCCESS); 8638 } 8639 8640 /*@ 8641 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8642 8643 Input Parameter: 8644 . dm - The `DMPLEX` object 8645 8646 Output Parameter: 8647 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8648 8649 Level: developer 8650 8651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8652 @*/ 8653 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8654 { 8655 DM_Plex *mesh = (DM_Plex *)dm->data; 8656 8657 PetscFunctionBegin; 8658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8659 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8660 *globalVertexNumbers = mesh->globalVertexNumbers; 8661 PetscFunctionReturn(PETSC_SUCCESS); 8662 } 8663 8664 /*@ 8665 DMPlexCreatePointNumbering - Create a global numbering for all points. 8666 8667 Collective 8668 8669 Input Parameter: 8670 . dm - The `DMPLEX` object 8671 8672 Output Parameter: 8673 . globalPointNumbers - Global numbers for all points on this process 8674 8675 Level: developer 8676 8677 Notes: 8678 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8679 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8680 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8681 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8682 8683 The partitioned mesh is 8684 ``` 8685 (2)--0--(3)--1--(4) (1)--0--(2) 8686 ``` 8687 and its global numbering is 8688 ``` 8689 (3)--0--(4)--1--(5)--2--(6) 8690 ``` 8691 Then the global numbering is provided as 8692 ``` 8693 [0] Number of indices in set 5 8694 [0] 0 0 8695 [0] 1 1 8696 [0] 2 3 8697 [0] 3 4 8698 [0] 4 -6 8699 [1] Number of indices in set 3 8700 [1] 0 2 8701 [1] 1 5 8702 [1] 2 6 8703 ``` 8704 8705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8706 @*/ 8707 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8708 { 8709 IS nums[4]; 8710 PetscInt depths[4], gdepths[4], starts[4]; 8711 PetscInt depth, d, shift = 0; 8712 PetscBool empty = PETSC_FALSE; 8713 8714 PetscFunctionBegin; 8715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8716 PetscCall(DMPlexGetDepth(dm, &depth)); 8717 // For unstratified meshes use dim instead of depth 8718 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8719 // If any stratum is empty, we must mark all empty 8720 for (d = 0; d <= depth; ++d) { 8721 PetscInt end; 8722 8723 depths[d] = depth - d; 8724 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8725 if (!(starts[d] - end)) empty = PETSC_TRUE; 8726 } 8727 if (empty) 8728 for (d = 0; d <= depth; ++d) { 8729 depths[d] = -1; 8730 starts[d] = -1; 8731 } 8732 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8733 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8734 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]); 8735 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8736 for (d = 0; d <= depth; ++d) { 8737 PetscInt pStart, pEnd, gsize; 8738 8739 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8740 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8741 shift += gsize; 8742 } 8743 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8744 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8745 PetscFunctionReturn(PETSC_SUCCESS); 8746 } 8747 8748 /*@ 8749 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8750 8751 Input Parameter: 8752 . dm - The `DMPLEX` object 8753 8754 Output Parameter: 8755 . ranks - The rank field 8756 8757 Options Database Key: 8758 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8759 8760 Level: intermediate 8761 8762 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8763 @*/ 8764 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8765 { 8766 DM rdm; 8767 PetscFE fe; 8768 PetscScalar *r; 8769 PetscMPIInt rank; 8770 DMPolytopeType ct; 8771 PetscInt dim, cStart, cEnd, c; 8772 PetscBool simplex; 8773 8774 PetscFunctionBeginUser; 8775 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8776 PetscAssertPointer(ranks, 2); 8777 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8778 PetscCall(DMClone(dm, &rdm)); 8779 PetscCall(DMGetDimension(rdm, &dim)); 8780 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8781 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8782 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8783 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8784 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8785 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8786 PetscCall(PetscFEDestroy(&fe)); 8787 PetscCall(DMCreateDS(rdm)); 8788 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8789 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8790 PetscCall(VecGetArray(*ranks, &r)); 8791 for (c = cStart; c < cEnd; ++c) { 8792 PetscScalar *lr; 8793 8794 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8795 if (lr) *lr = rank; 8796 } 8797 PetscCall(VecRestoreArray(*ranks, &r)); 8798 PetscCall(DMDestroy(&rdm)); 8799 PetscFunctionReturn(PETSC_SUCCESS); 8800 } 8801 8802 /*@ 8803 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8804 8805 Input Parameters: 8806 + dm - The `DMPLEX` 8807 - label - The `DMLabel` 8808 8809 Output Parameter: 8810 . val - The label value field 8811 8812 Options Database Key: 8813 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8814 8815 Level: intermediate 8816 8817 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8818 @*/ 8819 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8820 { 8821 DM rdm; 8822 PetscFE fe; 8823 PetscScalar *v; 8824 PetscInt dim, cStart, cEnd, c; 8825 8826 PetscFunctionBeginUser; 8827 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8828 PetscAssertPointer(label, 2); 8829 PetscAssertPointer(val, 3); 8830 PetscCall(DMClone(dm, &rdm)); 8831 PetscCall(DMGetDimension(rdm, &dim)); 8832 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8833 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8834 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8835 PetscCall(PetscFEDestroy(&fe)); 8836 PetscCall(DMCreateDS(rdm)); 8837 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8838 PetscCall(DMCreateGlobalVector(rdm, val)); 8839 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8840 PetscCall(VecGetArray(*val, &v)); 8841 for (c = cStart; c < cEnd; ++c) { 8842 PetscScalar *lv; 8843 PetscInt cval; 8844 8845 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8846 PetscCall(DMLabelGetValue(label, c, &cval)); 8847 *lv = cval; 8848 } 8849 PetscCall(VecRestoreArray(*val, &v)); 8850 PetscCall(DMDestroy(&rdm)); 8851 PetscFunctionReturn(PETSC_SUCCESS); 8852 } 8853 8854 /*@ 8855 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8856 8857 Input Parameter: 8858 . dm - The `DMPLEX` object 8859 8860 Level: developer 8861 8862 Notes: 8863 This is a useful diagnostic when creating meshes programmatically. 8864 8865 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8866 8867 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8868 @*/ 8869 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8870 { 8871 PetscSection coneSection, supportSection; 8872 const PetscInt *cone, *support; 8873 PetscInt coneSize, c, supportSize, s; 8874 PetscInt pStart, pEnd, p, pp, csize, ssize; 8875 PetscBool storagecheck = PETSC_TRUE; 8876 8877 PetscFunctionBegin; 8878 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8879 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8880 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8881 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8882 /* Check that point p is found in the support of its cone points, and vice versa */ 8883 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8884 for (p = pStart; p < pEnd; ++p) { 8885 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8886 PetscCall(DMPlexGetCone(dm, p, &cone)); 8887 for (c = 0; c < coneSize; ++c) { 8888 PetscBool dup = PETSC_FALSE; 8889 PetscInt d; 8890 for (d = c - 1; d >= 0; --d) { 8891 if (cone[c] == cone[d]) { 8892 dup = PETSC_TRUE; 8893 break; 8894 } 8895 } 8896 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8897 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8898 for (s = 0; s < supportSize; ++s) { 8899 if (support[s] == p) break; 8900 } 8901 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8902 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8903 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8904 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8905 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8906 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8907 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8908 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]); 8909 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8910 } 8911 } 8912 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8913 if (p != pp) { 8914 storagecheck = PETSC_FALSE; 8915 continue; 8916 } 8917 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8918 PetscCall(DMPlexGetSupport(dm, p, &support)); 8919 for (s = 0; s < supportSize; ++s) { 8920 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8921 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8922 for (c = 0; c < coneSize; ++c) { 8923 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8924 if (cone[c] != pp) { 8925 c = 0; 8926 break; 8927 } 8928 if (cone[c] == p) break; 8929 } 8930 if (c >= coneSize) { 8931 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8932 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8933 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8934 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8935 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8936 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8937 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8938 } 8939 } 8940 } 8941 if (storagecheck) { 8942 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8943 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8944 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8945 } 8946 PetscFunctionReturn(PETSC_SUCCESS); 8947 } 8948 8949 /* 8950 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. 8951 */ 8952 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8953 { 8954 DMPolytopeType cct; 8955 PetscInt ptpoints[4]; 8956 const PetscInt *cone, *ccone, *ptcone; 8957 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8958 8959 PetscFunctionBegin; 8960 *unsplit = 0; 8961 switch (ct) { 8962 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8963 ptpoints[npt++] = c; 8964 break; 8965 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8966 PetscCall(DMPlexGetCone(dm, c, &cone)); 8967 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8968 for (cp = 0; cp < coneSize; ++cp) { 8969 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8970 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8971 } 8972 break; 8973 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8974 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8975 PetscCall(DMPlexGetCone(dm, c, &cone)); 8976 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8977 for (cp = 0; cp < coneSize; ++cp) { 8978 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8979 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8980 for (ccp = 0; ccp < cconeSize; ++ccp) { 8981 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8982 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8983 PetscInt p; 8984 for (p = 0; p < npt; ++p) 8985 if (ptpoints[p] == ccone[ccp]) break; 8986 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8987 } 8988 } 8989 } 8990 break; 8991 default: 8992 break; 8993 } 8994 for (pt = 0; pt < npt; ++pt) { 8995 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8996 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8997 } 8998 PetscFunctionReturn(PETSC_SUCCESS); 8999 } 9000 9001 /*@ 9002 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9003 9004 Input Parameters: 9005 + dm - The `DMPLEX` object 9006 - cellHeight - Normally 0 9007 9008 Level: developer 9009 9010 Notes: 9011 This is a useful diagnostic when creating meshes programmatically. 9012 Currently applicable only to homogeneous simplex or tensor meshes. 9013 9014 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9015 9016 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9017 @*/ 9018 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9019 { 9020 DMPlexInterpolatedFlag interp; 9021 DMPolytopeType ct; 9022 PetscInt vStart, vEnd, cStart, cEnd, c; 9023 9024 PetscFunctionBegin; 9025 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9026 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9027 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9028 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9029 for (c = cStart; c < cEnd; ++c) { 9030 PetscInt *closure = NULL; 9031 PetscInt coneSize, closureSize, cl, Nv = 0; 9032 9033 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9034 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9035 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9036 if (interp == DMPLEX_INTERPOLATED_FULL) { 9037 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9038 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)); 9039 } 9040 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9041 for (cl = 0; cl < closureSize * 2; cl += 2) { 9042 const PetscInt p = closure[cl]; 9043 if ((p >= vStart) && (p < vEnd)) ++Nv; 9044 } 9045 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9046 /* Special Case: Tensor faces with identified vertices */ 9047 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9048 PetscInt unsplit; 9049 9050 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9051 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9052 } 9053 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)); 9054 } 9055 PetscFunctionReturn(PETSC_SUCCESS); 9056 } 9057 9058 /*@ 9059 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9060 9061 Collective 9062 9063 Input Parameters: 9064 + dm - The `DMPLEX` object 9065 - cellHeight - Normally 0 9066 9067 Level: developer 9068 9069 Notes: 9070 This is a useful diagnostic when creating meshes programmatically. 9071 This routine is only relevant for meshes that are fully interpolated across all ranks. 9072 It will error out if a partially interpolated mesh is given on some rank. 9073 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9074 9075 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9076 9077 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9078 @*/ 9079 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9080 { 9081 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9082 DMPlexInterpolatedFlag interpEnum; 9083 9084 PetscFunctionBegin; 9085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9086 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9087 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9088 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9089 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9090 PetscFunctionReturn(PETSC_SUCCESS); 9091 } 9092 9093 PetscCall(DMGetDimension(dm, &dim)); 9094 PetscCall(DMPlexGetDepth(dm, &depth)); 9095 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9096 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9097 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9098 for (c = cStart; c < cEnd; ++c) { 9099 const PetscInt *cone, *ornt, *faceSizes, *faces; 9100 const DMPolytopeType *faceTypes; 9101 DMPolytopeType ct; 9102 PetscInt numFaces, coneSize, f; 9103 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9104 9105 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9106 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9107 if (unsplit) continue; 9108 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9109 PetscCall(DMPlexGetCone(dm, c, &cone)); 9110 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9111 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9112 for (cl = 0; cl < closureSize * 2; cl += 2) { 9113 const PetscInt p = closure[cl]; 9114 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9115 } 9116 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9117 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); 9118 for (f = 0; f < numFaces; ++f) { 9119 DMPolytopeType fct; 9120 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9121 9122 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9123 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9124 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9125 const PetscInt p = fclosure[cl]; 9126 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9127 } 9128 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]); 9129 for (v = 0; v < fnumCorners; ++v) { 9130 if (fclosure[v] != faces[fOff + v]) { 9131 PetscInt v1; 9132 9133 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9134 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9135 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9136 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9137 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9138 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]); 9139 } 9140 } 9141 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9142 fOff += faceSizes[f]; 9143 } 9144 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9145 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9146 } 9147 } 9148 PetscFunctionReturn(PETSC_SUCCESS); 9149 } 9150 9151 /*@ 9152 DMPlexCheckGeometry - Check the geometry of mesh cells 9153 9154 Input Parameter: 9155 . dm - The `DMPLEX` object 9156 9157 Level: developer 9158 9159 Notes: 9160 This is a useful diagnostic when creating meshes programmatically. 9161 9162 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9163 9164 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9165 @*/ 9166 PetscErrorCode DMPlexCheckGeometry(DM dm) 9167 { 9168 Vec coordinates; 9169 PetscReal detJ, J[9], refVol = 1.0; 9170 PetscReal vol; 9171 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9172 9173 PetscFunctionBegin; 9174 PetscCall(DMGetDimension(dm, &dim)); 9175 PetscCall(DMGetCoordinateDim(dm, &dE)); 9176 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9177 PetscCall(DMPlexGetDepth(dm, &depth)); 9178 for (d = 0; d < dim; ++d) refVol *= 2.0; 9179 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9180 /* Make sure local coordinates are created, because that step is collective */ 9181 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9182 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9183 for (c = cStart; c < cEnd; ++c) { 9184 DMPolytopeType ct; 9185 PetscInt unsplit; 9186 PetscBool ignoreZeroVol = PETSC_FALSE; 9187 9188 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9189 switch (ct) { 9190 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9191 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9192 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9193 ignoreZeroVol = PETSC_TRUE; 9194 break; 9195 default: 9196 break; 9197 } 9198 switch (ct) { 9199 case DM_POLYTOPE_TRI_PRISM: 9200 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9201 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9202 case DM_POLYTOPE_PYRAMID: 9203 continue; 9204 default: 9205 break; 9206 } 9207 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9208 if (unsplit) continue; 9209 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9210 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); 9211 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9212 /* This should work with periodicity since DG coordinates should be used */ 9213 if (depth > 1) { 9214 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9215 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); 9216 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9217 } 9218 } 9219 PetscFunctionReturn(PETSC_SUCCESS); 9220 } 9221 9222 /*@ 9223 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9224 9225 Collective 9226 9227 Input Parameters: 9228 + dm - The `DMPLEX` object 9229 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9230 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9231 9232 Level: developer 9233 9234 Notes: 9235 This is mainly intended for debugging/testing purposes. 9236 9237 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9238 9239 Extra roots can come from periodic cuts, where additional points appear on the boundary 9240 9241 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9242 @*/ 9243 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9244 { 9245 PetscInt l, nleaves, nroots, overlap; 9246 const PetscInt *locals; 9247 const PetscSFNode *remotes; 9248 PetscBool distributed; 9249 MPI_Comm comm; 9250 PetscMPIInt rank; 9251 9252 PetscFunctionBegin; 9253 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9254 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9255 else pointSF = dm->sf; 9256 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9257 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9258 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9259 { 9260 PetscMPIInt mpiFlag; 9261 9262 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9263 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9264 } 9265 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9266 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9267 if (!distributed) { 9268 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); 9269 PetscFunctionReturn(PETSC_SUCCESS); 9270 } 9271 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); 9272 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9273 9274 /* Check SF graph is compatible with DMPlex chart */ 9275 { 9276 PetscInt pStart, pEnd, maxLeaf; 9277 9278 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9279 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9280 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9281 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9282 } 9283 9284 /* Check Point SF has no local points referenced */ 9285 for (l = 0; l < nleaves; l++) { 9286 PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index); 9287 } 9288 9289 /* Check there are no cells in interface */ 9290 if (!overlap) { 9291 PetscInt cellHeight, cStart, cEnd; 9292 9293 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9294 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9295 for (l = 0; l < nleaves; ++l) { 9296 const PetscInt point = locals ? locals[l] : l; 9297 9298 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9299 } 9300 } 9301 9302 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9303 { 9304 const PetscInt *rootdegree; 9305 9306 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9307 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9308 for (l = 0; l < nleaves; ++l) { 9309 const PetscInt point = locals ? locals[l] : l; 9310 const PetscInt *cone; 9311 PetscInt coneSize, c, idx; 9312 9313 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9314 PetscCall(DMPlexGetCone(dm, point, &cone)); 9315 for (c = 0; c < coneSize; ++c) { 9316 if (!rootdegree[cone[c]]) { 9317 if (locals) { 9318 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9319 } else { 9320 idx = (cone[c] < nleaves) ? cone[c] : -1; 9321 } 9322 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9323 } 9324 } 9325 } 9326 } 9327 PetscFunctionReturn(PETSC_SUCCESS); 9328 } 9329 9330 /*@ 9331 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9332 9333 Input Parameter: 9334 . dm - The `DMPLEX` object 9335 9336 Level: developer 9337 9338 Notes: 9339 This is a useful diagnostic when creating meshes programmatically. 9340 9341 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9342 9343 Currently does not include `DMPlexCheckCellShape()`. 9344 9345 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9346 @*/ 9347 PetscErrorCode DMPlexCheck(DM dm) 9348 { 9349 PetscInt cellHeight; 9350 9351 PetscFunctionBegin; 9352 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9353 PetscCall(DMPlexCheckSymmetry(dm)); 9354 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9355 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9356 PetscCall(DMPlexCheckGeometry(dm)); 9357 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9358 PetscCall(DMPlexCheckInterfaceCones(dm)); 9359 PetscFunctionReturn(PETSC_SUCCESS); 9360 } 9361 9362 typedef struct cell_stats { 9363 PetscReal min, max, sum, squaresum; 9364 PetscInt count; 9365 } cell_stats_t; 9366 9367 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9368 { 9369 PetscInt i, N = *len; 9370 9371 for (i = 0; i < N; i++) { 9372 cell_stats_t *A = (cell_stats_t *)a; 9373 cell_stats_t *B = (cell_stats_t *)b; 9374 9375 B->min = PetscMin(A->min, B->min); 9376 B->max = PetscMax(A->max, B->max); 9377 B->sum += A->sum; 9378 B->squaresum += A->squaresum; 9379 B->count += A->count; 9380 } 9381 } 9382 9383 /*@ 9384 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9385 9386 Collective 9387 9388 Input Parameters: 9389 + dm - The `DMPLEX` object 9390 . output - If true, statistics will be displayed on `stdout` 9391 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9392 9393 Level: developer 9394 9395 Notes: 9396 This is mainly intended for debugging/testing purposes. 9397 9398 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9399 9400 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9401 @*/ 9402 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9403 { 9404 DM dmCoarse; 9405 cell_stats_t stats, globalStats; 9406 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9407 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9408 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9409 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9410 PetscMPIInt rank, size; 9411 9412 PetscFunctionBegin; 9413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9414 stats.min = PETSC_MAX_REAL; 9415 stats.max = PETSC_MIN_REAL; 9416 stats.sum = stats.squaresum = 0.; 9417 stats.count = 0; 9418 9419 PetscCallMPI(MPI_Comm_size(comm, &size)); 9420 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9421 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9422 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9423 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9424 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9425 for (c = cStart; c < cEnd; c++) { 9426 PetscInt i; 9427 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9428 9429 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9430 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9431 for (i = 0; i < PetscSqr(cdim); ++i) { 9432 frobJ += J[i] * J[i]; 9433 frobInvJ += invJ[i] * invJ[i]; 9434 } 9435 cond2 = frobJ * frobInvJ; 9436 cond = PetscSqrtReal(cond2); 9437 9438 stats.min = PetscMin(stats.min, cond); 9439 stats.max = PetscMax(stats.max, cond); 9440 stats.sum += cond; 9441 stats.squaresum += cond2; 9442 stats.count++; 9443 if (output && cond > limit) { 9444 PetscSection coordSection; 9445 Vec coordsLocal; 9446 PetscScalar *coords = NULL; 9447 PetscInt Nv, d, clSize, cl, *closure = NULL; 9448 9449 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9450 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9451 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9452 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9453 for (i = 0; i < Nv / cdim; ++i) { 9454 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9455 for (d = 0; d < cdim; ++d) { 9456 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9457 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9458 } 9459 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9460 } 9461 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9462 for (cl = 0; cl < clSize * 2; cl += 2) { 9463 const PetscInt edge = closure[cl]; 9464 9465 if ((edge >= eStart) && (edge < eEnd)) { 9466 PetscReal len; 9467 9468 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9469 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9470 } 9471 } 9472 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9473 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9474 } 9475 } 9476 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9477 9478 if (size > 1) { 9479 PetscMPIInt blockLengths[2] = {4, 1}; 9480 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9481 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9482 MPI_Op statReduce; 9483 9484 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9485 PetscCallMPI(MPI_Type_commit(&statType)); 9486 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9487 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9488 PetscCallMPI(MPI_Op_free(&statReduce)); 9489 PetscCallMPI(MPI_Type_free(&statType)); 9490 } else { 9491 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9492 } 9493 if (rank == 0) { 9494 count = globalStats.count; 9495 min = globalStats.min; 9496 max = globalStats.max; 9497 mean = globalStats.sum / globalStats.count; 9498 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9499 } 9500 9501 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)); 9502 PetscCall(PetscFree2(J, invJ)); 9503 9504 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9505 if (dmCoarse) { 9506 PetscBool isplex; 9507 9508 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9509 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9510 } 9511 PetscFunctionReturn(PETSC_SUCCESS); 9512 } 9513 9514 /*@ 9515 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9516 orthogonal quality below given tolerance. 9517 9518 Collective 9519 9520 Input Parameters: 9521 + dm - The `DMPLEX` object 9522 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9523 - atol - [0, 1] Absolute tolerance for tagging cells. 9524 9525 Output Parameters: 9526 + OrthQual - `Vec` containing orthogonal quality per cell 9527 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9528 9529 Options Database Keys: 9530 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9531 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9532 9533 Level: intermediate 9534 9535 Notes: 9536 Orthogonal quality is given by the following formula\: 9537 9538 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9539 9540 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 9541 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9542 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9543 calculating the cosine of the angle between these vectors. 9544 9545 Orthogonal quality ranges from 1 (best) to 0 (worst). 9546 9547 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9548 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9549 9550 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9551 9552 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9553 @*/ 9554 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9555 { 9556 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9557 PetscInt *idx; 9558 PetscScalar *oqVals; 9559 const PetscScalar *cellGeomArr, *faceGeomArr; 9560 PetscReal *ci, *fi, *Ai; 9561 MPI_Comm comm; 9562 Vec cellgeom, facegeom; 9563 DM dmFace, dmCell; 9564 IS glob; 9565 ISLocalToGlobalMapping ltog; 9566 PetscViewer vwr; 9567 9568 PetscFunctionBegin; 9569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9570 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9571 PetscAssertPointer(OrthQual, 4); 9572 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9573 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9574 PetscCall(DMGetDimension(dm, &nc)); 9575 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9576 { 9577 DMPlexInterpolatedFlag interpFlag; 9578 9579 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9580 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9581 PetscMPIInt rank; 9582 9583 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9584 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9585 } 9586 } 9587 if (OrthQualLabel) { 9588 PetscAssertPointer(OrthQualLabel, 5); 9589 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9590 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9591 } else { 9592 *OrthQualLabel = NULL; 9593 } 9594 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9595 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9596 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9597 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9598 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9599 PetscCall(VecCreate(comm, OrthQual)); 9600 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9601 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9602 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9603 PetscCall(VecSetUp(*OrthQual)); 9604 PetscCall(ISDestroy(&glob)); 9605 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9606 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9607 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9608 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9609 PetscCall(VecGetDM(cellgeom, &dmCell)); 9610 PetscCall(VecGetDM(facegeom, &dmFace)); 9611 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9612 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9613 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9614 PetscInt cellarr[2], *adj = NULL; 9615 PetscScalar *cArr, *fArr; 9616 PetscReal minvalc = 1.0, minvalf = 1.0; 9617 PetscFVCellGeom *cg; 9618 9619 idx[cellIter] = cell - cStart; 9620 cellarr[0] = cell; 9621 /* Make indexing into cellGeom easier */ 9622 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9623 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9624 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9625 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9626 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9627 PetscInt i; 9628 const PetscInt neigh = adj[cellneigh]; 9629 PetscReal normci = 0, normfi = 0, normai = 0; 9630 PetscFVCellGeom *cgneigh; 9631 PetscFVFaceGeom *fg; 9632 9633 /* Don't count ourselves in the neighbor list */ 9634 if (neigh == cell) continue; 9635 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9636 cellarr[1] = neigh; 9637 { 9638 PetscInt numcovpts; 9639 const PetscInt *covpts; 9640 9641 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9642 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9643 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9644 } 9645 9646 /* Compute c_i, f_i and their norms */ 9647 for (i = 0; i < nc; i++) { 9648 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9649 fi[i] = fg->centroid[i] - cg->centroid[i]; 9650 Ai[i] = fg->normal[i]; 9651 normci += PetscPowReal(ci[i], 2); 9652 normfi += PetscPowReal(fi[i], 2); 9653 normai += PetscPowReal(Ai[i], 2); 9654 } 9655 normci = PetscSqrtReal(normci); 9656 normfi = PetscSqrtReal(normfi); 9657 normai = PetscSqrtReal(normai); 9658 9659 /* Normalize and compute for each face-cell-normal pair */ 9660 for (i = 0; i < nc; i++) { 9661 ci[i] = ci[i] / normci; 9662 fi[i] = fi[i] / normfi; 9663 Ai[i] = Ai[i] / normai; 9664 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9665 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9666 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9667 } 9668 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9669 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9670 } 9671 PetscCall(PetscFree(adj)); 9672 PetscCall(PetscFree2(cArr, fArr)); 9673 /* Defer to cell if they're equal */ 9674 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9675 if (OrthQualLabel) { 9676 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9677 } 9678 } 9679 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9680 PetscCall(VecAssemblyBegin(*OrthQual)); 9681 PetscCall(VecAssemblyEnd(*OrthQual)); 9682 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9683 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9684 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9685 if (OrthQualLabel) { 9686 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9687 } 9688 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9689 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9690 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9691 PetscFunctionReturn(PETSC_SUCCESS); 9692 } 9693 9694 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9695 * interpolator construction */ 9696 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9697 { 9698 PetscSection section, newSection, gsection; 9699 PetscSF sf; 9700 PetscBool hasConstraints, ghasConstraints; 9701 9702 PetscFunctionBegin; 9703 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9704 PetscAssertPointer(odm, 2); 9705 PetscCall(DMGetLocalSection(dm, §ion)); 9706 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9707 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9708 if (!ghasConstraints) { 9709 PetscCall(PetscObjectReference((PetscObject)dm)); 9710 *odm = dm; 9711 PetscFunctionReturn(PETSC_SUCCESS); 9712 } 9713 PetscCall(DMClone(dm, odm)); 9714 PetscCall(DMCopyFields(dm, *odm)); 9715 PetscCall(DMGetLocalSection(*odm, &newSection)); 9716 PetscCall(DMGetPointSF(*odm, &sf)); 9717 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9718 PetscCall(DMSetGlobalSection(*odm, gsection)); 9719 PetscCall(PetscSectionDestroy(&gsection)); 9720 PetscFunctionReturn(PETSC_SUCCESS); 9721 } 9722 9723 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9724 { 9725 DM dmco, dmfo; 9726 Mat interpo; 9727 Vec rscale; 9728 Vec cglobalo, clocal; 9729 Vec fglobal, fglobalo, flocal; 9730 PetscBool regular; 9731 9732 PetscFunctionBegin; 9733 PetscCall(DMGetFullDM(dmc, &dmco)); 9734 PetscCall(DMGetFullDM(dmf, &dmfo)); 9735 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9736 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9737 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9738 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9739 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9740 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9741 PetscCall(VecSet(cglobalo, 0.)); 9742 PetscCall(VecSet(clocal, 0.)); 9743 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9744 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9745 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9746 PetscCall(VecSet(fglobal, 0.)); 9747 PetscCall(VecSet(fglobalo, 0.)); 9748 PetscCall(VecSet(flocal, 0.)); 9749 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9750 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9751 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9752 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9753 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9754 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9755 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9756 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9757 *shift = fglobal; 9758 PetscCall(VecDestroy(&flocal)); 9759 PetscCall(VecDestroy(&fglobalo)); 9760 PetscCall(VecDestroy(&clocal)); 9761 PetscCall(VecDestroy(&cglobalo)); 9762 PetscCall(VecDestroy(&rscale)); 9763 PetscCall(MatDestroy(&interpo)); 9764 PetscCall(DMDestroy(&dmfo)); 9765 PetscCall(DMDestroy(&dmco)); 9766 PetscFunctionReturn(PETSC_SUCCESS); 9767 } 9768 9769 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9770 { 9771 PetscObject shifto; 9772 Vec shift; 9773 9774 PetscFunctionBegin; 9775 if (!interp) { 9776 Vec rscale; 9777 9778 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9779 PetscCall(VecDestroy(&rscale)); 9780 } else { 9781 PetscCall(PetscObjectReference((PetscObject)interp)); 9782 } 9783 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9784 if (!shifto) { 9785 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9786 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9787 shifto = (PetscObject)shift; 9788 PetscCall(VecDestroy(&shift)); 9789 } 9790 shift = (Vec)shifto; 9791 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9792 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9793 PetscCall(MatDestroy(&interp)); 9794 PetscFunctionReturn(PETSC_SUCCESS); 9795 } 9796 9797 /* Pointwise interpolation 9798 Just code FEM for now 9799 u^f = I u^c 9800 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9801 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9802 I_{ij} = psi^f_i phi^c_j 9803 */ 9804 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9805 { 9806 PetscSection gsc, gsf; 9807 PetscInt m, n; 9808 void *ctx; 9809 DM cdm; 9810 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9811 9812 PetscFunctionBegin; 9813 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9814 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9815 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9816 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9817 9818 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9819 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9820 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9821 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9822 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9823 9824 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9825 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9826 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9827 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9828 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9829 if (scaling) { 9830 /* Use naive scaling */ 9831 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9832 } 9833 PetscFunctionReturn(PETSC_SUCCESS); 9834 } 9835 9836 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9837 { 9838 VecScatter ctx; 9839 9840 PetscFunctionBegin; 9841 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9842 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9843 PetscCall(VecScatterDestroy(&ctx)); 9844 PetscFunctionReturn(PETSC_SUCCESS); 9845 } 9846 9847 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[]) 9848 { 9849 const PetscInt Nc = uOff[1] - uOff[0]; 9850 PetscInt c; 9851 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9852 } 9853 9854 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9855 { 9856 DM dmc; 9857 PetscDS ds; 9858 Vec ones, locmass; 9859 IS cellIS; 9860 PetscFormKey key; 9861 PetscInt depth; 9862 9863 PetscFunctionBegin; 9864 PetscCall(DMClone(dm, &dmc)); 9865 PetscCall(DMCopyDisc(dm, dmc)); 9866 PetscCall(DMGetDS(dmc, &ds)); 9867 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9868 PetscCall(DMCreateGlobalVector(dmc, mass)); 9869 PetscCall(DMGetLocalVector(dmc, &ones)); 9870 PetscCall(DMGetLocalVector(dmc, &locmass)); 9871 PetscCall(DMPlexGetDepth(dmc, &depth)); 9872 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9873 PetscCall(VecSet(locmass, 0.0)); 9874 PetscCall(VecSet(ones, 1.0)); 9875 key.label = NULL; 9876 key.value = 0; 9877 key.field = 0; 9878 key.part = 0; 9879 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9880 PetscCall(ISDestroy(&cellIS)); 9881 PetscCall(VecSet(*mass, 0.0)); 9882 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9883 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9884 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9885 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9886 PetscCall(DMDestroy(&dmc)); 9887 PetscFunctionReturn(PETSC_SUCCESS); 9888 } 9889 9890 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9891 { 9892 PetscSection gsc, gsf; 9893 PetscInt m, n; 9894 void *ctx; 9895 DM cdm; 9896 PetscBool regular; 9897 9898 PetscFunctionBegin; 9899 if (dmFine == dmCoarse) { 9900 DM dmc; 9901 PetscDS ds; 9902 PetscWeakForm wf; 9903 Vec u; 9904 IS cellIS; 9905 PetscFormKey key; 9906 PetscInt depth; 9907 9908 PetscCall(DMClone(dmFine, &dmc)); 9909 PetscCall(DMCopyDisc(dmFine, dmc)); 9910 PetscCall(DMGetDS(dmc, &ds)); 9911 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9912 PetscCall(PetscWeakFormClear(wf)); 9913 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9914 PetscCall(DMCreateMatrix(dmc, mass)); 9915 PetscCall(DMGetLocalVector(dmc, &u)); 9916 PetscCall(DMPlexGetDepth(dmc, &depth)); 9917 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9918 PetscCall(MatZeroEntries(*mass)); 9919 key.label = NULL; 9920 key.value = 0; 9921 key.field = 0; 9922 key.part = 0; 9923 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9924 PetscCall(ISDestroy(&cellIS)); 9925 PetscCall(DMRestoreLocalVector(dmc, &u)); 9926 PetscCall(DMDestroy(&dmc)); 9927 } else { 9928 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9929 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9930 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9931 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9932 9933 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9934 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9935 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9936 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9937 9938 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9939 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9940 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9941 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9942 } 9943 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9944 PetscFunctionReturn(PETSC_SUCCESS); 9945 } 9946 9947 /*@ 9948 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9949 9950 Input Parameter: 9951 . dm - The `DMPLEX` object 9952 9953 Output Parameter: 9954 . regular - The flag 9955 9956 Level: intermediate 9957 9958 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9959 @*/ 9960 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9961 { 9962 PetscFunctionBegin; 9963 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9964 PetscAssertPointer(regular, 2); 9965 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9966 PetscFunctionReturn(PETSC_SUCCESS); 9967 } 9968 9969 /*@ 9970 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9971 9972 Input Parameters: 9973 + dm - The `DMPLEX` object 9974 - regular - The flag 9975 9976 Level: intermediate 9977 9978 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9979 @*/ 9980 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9981 { 9982 PetscFunctionBegin; 9983 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9984 ((DM_Plex *)dm->data)->regularRefinement = regular; 9985 PetscFunctionReturn(PETSC_SUCCESS); 9986 } 9987 9988 /*@ 9989 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9990 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9991 9992 Not Collective 9993 9994 Input Parameter: 9995 . dm - The `DMPLEX` object 9996 9997 Output Parameters: 9998 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9999 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10000 10001 Level: intermediate 10002 10003 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10004 @*/ 10005 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10006 { 10007 DM_Plex *plex = (DM_Plex *)dm->data; 10008 10009 PetscFunctionBegin; 10010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10011 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10012 if (anchorSection) *anchorSection = plex->anchorSection; 10013 if (anchorIS) *anchorIS = plex->anchorIS; 10014 PetscFunctionReturn(PETSC_SUCCESS); 10015 } 10016 10017 /*@ 10018 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10019 10020 Collective 10021 10022 Input Parameters: 10023 + dm - The `DMPLEX` object 10024 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10025 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10026 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10027 10028 Level: intermediate 10029 10030 Notes: 10031 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10032 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10033 combination of other points' degrees of freedom. 10034 10035 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10036 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10037 10038 The reference counts of `anchorSection` and `anchorIS` are incremented. 10039 10040 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10041 @*/ 10042 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10043 { 10044 DM_Plex *plex = (DM_Plex *)dm->data; 10045 PetscMPIInt result; 10046 10047 PetscFunctionBegin; 10048 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10049 if (anchorSection) { 10050 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10051 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10052 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10053 } 10054 if (anchorIS) { 10055 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10056 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10057 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10058 } 10059 10060 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10061 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10062 plex->anchorSection = anchorSection; 10063 10064 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10065 PetscCall(ISDestroy(&plex->anchorIS)); 10066 plex->anchorIS = anchorIS; 10067 10068 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10069 PetscInt size, a, pStart, pEnd; 10070 const PetscInt *anchors; 10071 10072 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10073 PetscCall(ISGetLocalSize(anchorIS, &size)); 10074 PetscCall(ISGetIndices(anchorIS, &anchors)); 10075 for (a = 0; a < size; a++) { 10076 PetscInt p; 10077 10078 p = anchors[a]; 10079 if (p >= pStart && p < pEnd) { 10080 PetscInt dof; 10081 10082 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10083 if (dof) { 10084 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10085 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10086 } 10087 } 10088 } 10089 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10090 } 10091 /* reset the generic constraints */ 10092 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10093 PetscFunctionReturn(PETSC_SUCCESS); 10094 } 10095 10096 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10097 { 10098 PetscSection anchorSection; 10099 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10100 10101 PetscFunctionBegin; 10102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10103 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10104 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10105 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10106 if (numFields) { 10107 PetscInt f; 10108 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10109 10110 for (f = 0; f < numFields; f++) { 10111 PetscInt numComp; 10112 10113 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10114 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10115 } 10116 } 10117 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10118 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10119 pStart = PetscMax(pStart, sStart); 10120 pEnd = PetscMin(pEnd, sEnd); 10121 pEnd = PetscMax(pStart, pEnd); 10122 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10123 for (p = pStart; p < pEnd; p++) { 10124 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10125 if (dof) { 10126 PetscCall(PetscSectionGetDof(section, p, &dof)); 10127 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10128 for (f = 0; f < numFields; f++) { 10129 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10130 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10131 } 10132 } 10133 } 10134 PetscCall(PetscSectionSetUp(*cSec)); 10135 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10136 PetscFunctionReturn(PETSC_SUCCESS); 10137 } 10138 10139 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10140 { 10141 PetscSection aSec; 10142 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10143 const PetscInt *anchors; 10144 PetscInt numFields, f; 10145 IS aIS; 10146 MatType mtype; 10147 PetscBool iscuda, iskokkos; 10148 10149 PetscFunctionBegin; 10150 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10151 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10152 PetscCall(PetscSectionGetStorageSize(section, &n)); 10153 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10154 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10155 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10156 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10157 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10158 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10159 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10160 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10161 else mtype = MATSEQAIJ; 10162 PetscCall(MatSetType(*cMat, mtype)); 10163 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10164 PetscCall(ISGetIndices(aIS, &anchors)); 10165 /* cSec will be a subset of aSec and section */ 10166 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10167 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10168 PetscCall(PetscMalloc1(m + 1, &i)); 10169 i[0] = 0; 10170 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10171 for (p = pStart; p < pEnd; p++) { 10172 PetscInt rDof, rOff, r; 10173 10174 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10175 if (!rDof) continue; 10176 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10177 if (numFields) { 10178 for (f = 0; f < numFields; f++) { 10179 annz = 0; 10180 for (r = 0; r < rDof; r++) { 10181 a = anchors[rOff + r]; 10182 if (a < sStart || a >= sEnd) continue; 10183 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10184 annz += aDof; 10185 } 10186 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10187 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10188 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10189 } 10190 } else { 10191 annz = 0; 10192 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10193 for (q = 0; q < dof; q++) { 10194 a = anchors[rOff + q]; 10195 if (a < sStart || a >= sEnd) continue; 10196 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10197 annz += aDof; 10198 } 10199 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10200 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10201 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10202 } 10203 } 10204 nnz = i[m]; 10205 PetscCall(PetscMalloc1(nnz, &j)); 10206 offset = 0; 10207 for (p = pStart; p < pEnd; p++) { 10208 if (numFields) { 10209 for (f = 0; f < numFields; f++) { 10210 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10211 for (q = 0; q < dof; q++) { 10212 PetscInt rDof, rOff, r; 10213 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10214 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10215 for (r = 0; r < rDof; r++) { 10216 PetscInt s; 10217 10218 a = anchors[rOff + r]; 10219 if (a < sStart || a >= sEnd) continue; 10220 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10221 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10222 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10223 } 10224 } 10225 } 10226 } else { 10227 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10228 for (q = 0; q < dof; q++) { 10229 PetscInt rDof, rOff, r; 10230 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10231 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10232 for (r = 0; r < rDof; r++) { 10233 PetscInt s; 10234 10235 a = anchors[rOff + r]; 10236 if (a < sStart || a >= sEnd) continue; 10237 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10238 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10239 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10240 } 10241 } 10242 } 10243 } 10244 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10245 PetscCall(PetscFree(i)); 10246 PetscCall(PetscFree(j)); 10247 PetscCall(ISRestoreIndices(aIS, &anchors)); 10248 PetscFunctionReturn(PETSC_SUCCESS); 10249 } 10250 10251 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10252 { 10253 DM_Plex *plex = (DM_Plex *)dm->data; 10254 PetscSection anchorSection, section, cSec; 10255 Mat cMat; 10256 10257 PetscFunctionBegin; 10258 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10259 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10260 if (anchorSection) { 10261 PetscInt Nf; 10262 10263 PetscCall(DMGetLocalSection(dm, §ion)); 10264 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10265 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10266 PetscCall(DMGetNumFields(dm, &Nf)); 10267 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10268 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10269 PetscCall(PetscSectionDestroy(&cSec)); 10270 PetscCall(MatDestroy(&cMat)); 10271 } 10272 PetscFunctionReturn(PETSC_SUCCESS); 10273 } 10274 10275 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10276 { 10277 IS subis; 10278 PetscSection section, subsection; 10279 10280 PetscFunctionBegin; 10281 PetscCall(DMGetLocalSection(dm, §ion)); 10282 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10283 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10284 /* Create subdomain */ 10285 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10286 /* Create submodel */ 10287 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10288 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10289 PetscCall(DMSetLocalSection(*subdm, subsection)); 10290 PetscCall(PetscSectionDestroy(&subsection)); 10291 PetscCall(DMCopyDisc(dm, *subdm)); 10292 /* Create map from submodel to global model */ 10293 if (is) { 10294 PetscSection sectionGlobal, subsectionGlobal; 10295 IS spIS; 10296 const PetscInt *spmap; 10297 PetscInt *subIndices; 10298 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10299 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10300 10301 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10302 PetscCall(ISGetIndices(spIS, &spmap)); 10303 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10304 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10305 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10306 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10307 for (p = pStart; p < pEnd; ++p) { 10308 PetscInt gdof, pSubSize = 0; 10309 10310 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10311 if (gdof > 0) { 10312 for (f = 0; f < Nf; ++f) { 10313 PetscInt fdof, fcdof; 10314 10315 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10316 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10317 pSubSize += fdof - fcdof; 10318 } 10319 subSize += pSubSize; 10320 if (pSubSize) { 10321 if (bs < 0) { 10322 bs = pSubSize; 10323 } else if (bs != pSubSize) { 10324 /* Layout does not admit a pointwise block size */ 10325 bs = 1; 10326 } 10327 } 10328 } 10329 } 10330 /* Must have same blocksize on all procs (some might have no points) */ 10331 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10332 bsLocal[1] = bs; 10333 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10334 if (bsMinMax[0] != bsMinMax[1]) { 10335 bs = 1; 10336 } else { 10337 bs = bsMinMax[0]; 10338 } 10339 PetscCall(PetscMalloc1(subSize, &subIndices)); 10340 for (p = pStart; p < pEnd; ++p) { 10341 PetscInt gdof, goff; 10342 10343 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10344 if (gdof > 0) { 10345 const PetscInt point = spmap[p]; 10346 10347 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10348 for (f = 0; f < Nf; ++f) { 10349 PetscInt fdof, fcdof, fc, f2, poff = 0; 10350 10351 /* Can get rid of this loop by storing field information in the global section */ 10352 for (f2 = 0; f2 < f; ++f2) { 10353 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10354 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10355 poff += fdof - fcdof; 10356 } 10357 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10358 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10359 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10360 } 10361 } 10362 } 10363 PetscCall(ISRestoreIndices(spIS, &spmap)); 10364 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10365 if (bs > 1) { 10366 /* We need to check that the block size does not come from non-contiguous fields */ 10367 PetscInt i, j, set = 1; 10368 for (i = 0; i < subSize; i += bs) { 10369 for (j = 0; j < bs; ++j) { 10370 if (subIndices[i + j] != subIndices[i] + j) { 10371 set = 0; 10372 break; 10373 } 10374 } 10375 } 10376 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10377 } 10378 /* Attach nullspace */ 10379 for (f = 0; f < Nf; ++f) { 10380 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10381 if ((*subdm)->nullspaceConstructors[f]) break; 10382 } 10383 if (f < Nf) { 10384 MatNullSpace nullSpace; 10385 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10386 10387 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10388 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10389 } 10390 } 10391 PetscFunctionReturn(PETSC_SUCCESS); 10392 } 10393 10394 /*@ 10395 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10396 10397 Input Parameters: 10398 + dm - The `DM` 10399 - dummy - unused argument 10400 10401 Options Database Key: 10402 . -dm_plex_monitor_throughput - Activate the monitor 10403 10404 Level: developer 10405 10406 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10407 @*/ 10408 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10409 { 10410 PetscLogHandler default_handler; 10411 10412 PetscFunctionBegin; 10413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10414 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10415 if (default_handler) { 10416 PetscLogEvent event; 10417 PetscEventPerfInfo eventInfo; 10418 PetscReal cellRate, flopRate; 10419 PetscInt cStart, cEnd, Nf, N; 10420 const char *name; 10421 10422 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10423 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10424 PetscCall(DMGetNumFields(dm, &Nf)); 10425 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10426 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10427 N = (cEnd - cStart) * Nf * eventInfo.count; 10428 flopRate = eventInfo.flops / eventInfo.time; 10429 cellRate = N / eventInfo.time; 10430 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))); 10431 } else { 10432 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."); 10433 } 10434 PetscFunctionReturn(PETSC_SUCCESS); 10435 } 10436