1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 89 90 PetscFunctionBegin; 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 93 PetscCall(ISGetLocalSize(valueIS, &Nct)); 94 PetscCall(ISGetIndices(valueIS, &ctypes)); 95 if (!Nct) cS = cE = 0; 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 } 114 PetscCall(ISDestroy(&valueIS)); 115 // Reset label for fast lookup 116 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 117 if (cStart) *cStart = cS; 118 if (cEnd) *cEnd = cE; 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 123 { 124 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 125 PetscInt *sStart, *sEnd; 126 PetscViewerVTKFieldType *ft; 127 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 128 DMLabel depthLabel, ctLabel; 129 130 PetscFunctionBegin; 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 } 162 163 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 164 *types = 0; 165 166 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 167 if (globalvcdof[c]) ++(*types); 168 } 169 170 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 171 t = 0; 172 if (globalvcdof[DM_NUM_POLYTOPES]) { 173 sStart[t] = vStart; 174 sEnd[t] = vEnd; 175 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 176 ++t; 177 } 178 179 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 180 if (globalvcdof[c]) { 181 const DMPolytopeType ict = (DMPolytopeType)c; 182 183 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 184 sStart[t] = cStart; 185 sEnd[t] = cEnd; 186 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 187 ++t; 188 } 189 } 190 191 if (!*types) { 192 if (field >= 0) { 193 const char *fieldname; 194 195 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 196 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 197 } else { 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 199 } 200 } 201 202 *ssStart = sStart; 203 *ssEnd = sEnd; 204 *sft = ft; 205 PetscFunctionReturn(PETSC_SUCCESS); 206 } 207 208 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 209 { 210 PetscFunctionBegin; 211 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 216 { 217 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 218 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 219 220 PetscFunctionBegin; 221 *ft = PETSC_VTK_INVALID; 222 PetscCall(DMGetCoordinateDim(dm, &cdim)); 223 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 224 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 225 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 226 if (field >= 0) { 227 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 228 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 229 } else { 230 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 231 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 232 } 233 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 234 if (globalvcdof[0]) { 235 *sStart = vStart; 236 *sEnd = vEnd; 237 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 238 else *ft = PETSC_VTK_POINT_FIELD; 239 } else if (globalvcdof[1]) { 240 *sStart = cStart; 241 *sEnd = cEnd; 242 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 243 else *ft = PETSC_VTK_CELL_FIELD; 244 } else { 245 if (field >= 0) { 246 const char *fieldname; 247 248 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 249 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 250 } else { 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 252 } 253 } 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 /*@ 258 DMPlexVecView1D - Plot many 1D solutions on the same line graph 259 260 Collective 261 262 Input Parameters: 263 + dm - The `DMPLEX` object 264 . n - The number of vectors 265 . u - The array of local vectors 266 - viewer - The `PetscViewer` 267 268 Level: advanced 269 270 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 271 @*/ 272 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 273 { 274 PetscDS ds; 275 PetscDraw draw = NULL; 276 PetscDrawLG lg; 277 Vec coordinates; 278 const PetscScalar *coords, **sol; 279 PetscReal *vals; 280 PetscInt *Nc; 281 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 282 char **names; 283 284 PetscFunctionBegin; 285 PetscCall(DMGetDS(dm, &ds)); 286 PetscCall(PetscDSGetNumFields(ds, &Nf)); 287 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 288 PetscCall(PetscDSGetComponents(ds, &Nc)); 289 290 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 291 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 292 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 293 294 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 295 for (i = 0, l = 0; i < n; ++i) { 296 const char *vname; 297 298 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 299 for (f = 0; f < Nf; ++f) { 300 PetscObject disc; 301 const char *fname; 302 char tmpname[PETSC_MAX_PATH_LEN]; 303 304 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 305 /* TODO Create names for components */ 306 for (c = 0; c < Nc[f]; ++c, ++l) { 307 PetscCall(PetscObjectGetName(disc, &fname)); 308 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 309 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 311 PetscCall(PetscStrallocpy(tmpname, &names[l])); 312 } 313 } 314 } 315 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 316 /* Just add P_1 support for now */ 317 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 318 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 319 PetscCall(VecGetArrayRead(coordinates, &coords)); 320 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 321 for (v = vStart; v < vEnd; ++v) { 322 PetscScalar *x, *svals; 323 324 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 325 for (i = 0; i < n; ++i) { 326 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 327 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 328 } 329 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 330 } 331 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 332 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 333 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 334 PetscCall(PetscFree3(sol, names, vals)); 335 336 PetscCall(PetscDrawLGDraw(lg)); 337 PetscCall(PetscDrawLGDestroy(&lg)); 338 PetscFunctionReturn(PETSC_SUCCESS); 339 } 340 341 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 342 { 343 DM dm; 344 345 PetscFunctionBegin; 346 PetscCall(VecGetDM(u, &dm)); 347 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 352 { 353 DM dm; 354 PetscSection s; 355 PetscDraw draw, popup; 356 DM cdm; 357 PetscSection coordSection; 358 Vec coordinates; 359 const PetscScalar *array; 360 PetscReal lbound[3], ubound[3]; 361 PetscReal vbound[2], time; 362 PetscBool flg; 363 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 364 const char *name; 365 char title[PETSC_MAX_PATH_LEN]; 366 367 PetscFunctionBegin; 368 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 369 PetscCall(VecGetDM(v, &dm)); 370 PetscCall(DMGetCoordinateDim(dm, &dim)); 371 PetscCall(DMGetLocalSection(dm, &s)); 372 PetscCall(PetscSectionGetNumFields(s, &Nf)); 373 PetscCall(DMGetCoarsenLevel(dm, &level)); 374 PetscCall(DMGetCoordinateDM(dm, &cdm)); 375 PetscCall(DMGetLocalSection(cdm, &coordSection)); 376 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 377 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 378 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 379 380 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 381 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 382 383 PetscCall(VecGetLocalSize(coordinates, &N)); 384 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 385 PetscCall(PetscDrawClear(draw)); 386 387 /* Could implement something like DMDASelectFields() */ 388 for (f = 0; f < Nf; ++f) { 389 DM fdm = dm; 390 Vec fv = v; 391 IS fis; 392 char prefix[PETSC_MAX_PATH_LEN]; 393 const char *fname; 394 395 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 396 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 397 398 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 399 else prefix[0] = '\0'; 400 if (Nf > 1) { 401 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 402 PetscCall(VecGetSubVector(v, fis, &fv)); 403 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 404 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 405 } 406 for (comp = 0; comp < Nc; ++comp, ++w) { 407 PetscInt nmax = 2; 408 409 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 410 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 411 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 412 PetscCall(PetscDrawSetTitle(draw, title)); 413 414 /* TODO Get max and min only for this component */ 415 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 416 if (!flg) { 417 PetscCall(VecMin(fv, NULL, &vbound[0])); 418 PetscCall(VecMax(fv, NULL, &vbound[1])); 419 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 420 } 421 422 PetscCall(PetscDrawGetPopup(draw, &popup)); 423 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 424 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 425 PetscCall(VecGetArrayRead(fv, &array)); 426 for (c = cStart; c < cEnd; ++c) { 427 PetscScalar *coords = NULL, *a = NULL; 428 const PetscScalar *coords_arr; 429 PetscBool isDG; 430 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 431 432 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 433 if (a) { 434 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 435 color[1] = color[2] = color[3] = color[0]; 436 } else { 437 PetscScalar *vals = NULL; 438 PetscInt numVals, va; 439 440 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 441 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); 442 switch (numVals / Nc) { 443 case 3: /* P1 Triangle */ 444 case 4: /* P1 Quadrangle */ 445 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 446 break; 447 case 6: /* P2 Triangle */ 448 case 8: /* P2 Quadrangle */ 449 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 450 break; 451 default: 452 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 453 } 454 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 455 } 456 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 457 switch (numCoords) { 458 case 6: 459 case 12: /* Localized triangle */ 460 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])); 461 break; 462 case 8: 463 case 16: /* Localized quadrilateral */ 464 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])); 465 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])); 466 break; 467 default: 468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 469 } 470 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 471 } 472 PetscCall(VecRestoreArrayRead(fv, &array)); 473 PetscCall(PetscDrawFlush(draw)); 474 PetscCall(PetscDrawPause(draw)); 475 PetscCall(PetscDrawSave(draw)); 476 } 477 if (Nf > 1) { 478 PetscCall(VecRestoreSubVector(v, fis, &fv)); 479 PetscCall(ISDestroy(&fis)); 480 PetscCall(DMDestroy(&fdm)); 481 } 482 } 483 PetscFunctionReturn(PETSC_SUCCESS); 484 } 485 486 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 487 { 488 DM dm; 489 PetscDraw draw; 490 PetscInt dim; 491 PetscBool isnull; 492 493 PetscFunctionBegin; 494 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 495 PetscCall(PetscDrawIsNull(draw, &isnull)); 496 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 497 498 PetscCall(VecGetDM(v, &dm)); 499 PetscCall(DMGetCoordinateDim(dm, &dim)); 500 switch (dim) { 501 case 1: 502 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 503 break; 504 case 2: 505 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 506 break; 507 default: 508 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 509 } 510 PetscFunctionReturn(PETSC_SUCCESS); 511 } 512 513 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 514 { 515 DM dm; 516 Vec locv; 517 const char *name; 518 PetscSection section; 519 PetscInt pStart, pEnd; 520 PetscInt numFields; 521 PetscViewerVTKFieldType ft; 522 523 PetscFunctionBegin; 524 PetscCall(VecGetDM(v, &dm)); 525 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 526 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 527 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 528 PetscCall(VecCopy(v, locv)); 529 PetscCall(DMGetLocalSection(dm, §ion)); 530 PetscCall(PetscSectionGetNumFields(section, &numFields)); 531 if (!numFields) { 532 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 533 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 534 } else { 535 PetscInt f; 536 537 for (f = 0; f < numFields; f++) { 538 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 539 if (ft == PETSC_VTK_INVALID) continue; 540 PetscCall(PetscObjectReference((PetscObject)locv)); 541 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 542 } 543 PetscCall(VecDestroy(&locv)); 544 } 545 PetscFunctionReturn(PETSC_SUCCESS); 546 } 547 548 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 549 { 550 DM dm; 551 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 552 553 PetscFunctionBegin; 554 PetscCall(VecGetDM(v, &dm)); 555 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 561 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 562 PetscInt i, numFields; 563 PetscObject fe; 564 PetscBool fem = PETSC_FALSE; 565 Vec locv = v; 566 const char *name; 567 PetscInt step; 568 PetscReal time; 569 570 PetscCall(DMGetNumFields(dm, &numFields)); 571 for (i = 0; i < numFields; i++) { 572 PetscCall(DMGetField(dm, i, NULL, &fe)); 573 if (fe->classid == PETSCFE_CLASSID) { 574 fem = PETSC_TRUE; 575 break; 576 } 577 } 578 if (fem) { 579 PetscObject isZero; 580 581 PetscCall(DMGetLocalVector(dm, &locv)); 582 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 583 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 584 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 585 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 586 PetscCall(VecCopy(v, locv)); 587 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 588 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 589 } 590 if (isvtk) { 591 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 592 } else if (ishdf5) { 593 #if defined(PETSC_HAVE_HDF5) 594 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 595 #else 596 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 597 #endif 598 } else if (isdraw) { 599 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 600 } else if (isglvis) { 601 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 602 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 603 PetscCall(VecView_GLVis(locv, viewer)); 604 } else if (iscgns) { 605 #if defined(PETSC_HAVE_CGNS) 606 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 607 #else 608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 609 #endif 610 } 611 if (fem) { 612 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 613 PetscCall(DMRestoreLocalVector(dm, &locv)); 614 } 615 } else { 616 PetscBool isseq; 617 618 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 619 if (isseq) PetscCall(VecView_Seq(v, viewer)); 620 else PetscCall(VecView_MPI(v, viewer)); 621 } 622 PetscFunctionReturn(PETSC_SUCCESS); 623 } 624 625 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 626 { 627 DM dm; 628 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 629 630 PetscFunctionBegin; 631 PetscCall(VecGetDM(v, &dm)); 632 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 633 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 639 if (isvtk || isdraw || isglvis || iscgns) { 640 Vec locv; 641 PetscObject isZero; 642 const char *name; 643 644 PetscCall(DMGetLocalVector(dm, &locv)); 645 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 646 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 647 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 648 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 649 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 650 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 651 PetscCall(VecView_Plex_Local(locv, viewer)); 652 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 653 PetscCall(DMRestoreLocalVector(dm, &locv)); 654 } else if (ishdf5) { 655 #if defined(PETSC_HAVE_HDF5) 656 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 657 #else 658 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 659 #endif 660 } else if (isexodusii) { 661 #if defined(PETSC_HAVE_EXODUSII) 662 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 663 #else 664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 665 #endif 666 } else { 667 PetscBool isseq; 668 669 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 670 if (isseq) PetscCall(VecView_Seq(v, viewer)); 671 else PetscCall(VecView_MPI(v, viewer)); 672 } 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 677 { 678 DM dm; 679 MPI_Comm comm; 680 PetscViewerFormat format; 681 Vec v; 682 PetscBool isvtk, ishdf5; 683 684 PetscFunctionBegin; 685 PetscCall(VecGetDM(originalv, &dm)); 686 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 687 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 688 PetscCall(PetscViewerGetFormat(viewer, &format)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 691 if (format == PETSC_VIEWER_NATIVE) { 692 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 693 /* this need a better fix */ 694 if (dm->useNatural) { 695 if (dm->sfNatural) { 696 const char *vecname; 697 PetscInt n, nroots; 698 699 PetscCall(VecGetLocalSize(originalv, &n)); 700 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 701 if (n == nroots) { 702 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 703 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 704 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 705 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 706 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 707 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 709 } else v = originalv; 710 } else v = originalv; 711 712 if (ishdf5) { 713 #if defined(PETSC_HAVE_HDF5) 714 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 715 #else 716 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 717 #endif 718 } else if (isvtk) { 719 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 720 } else { 721 PetscBool isseq; 722 723 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 724 if (isseq) PetscCall(VecView_Seq(v, viewer)); 725 else PetscCall(VecView_MPI(v, viewer)); 726 } 727 if (v != originalv) PetscCall(VecDestroy(&v)); 728 PetscFunctionReturn(PETSC_SUCCESS); 729 } 730 731 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 732 { 733 DM dm; 734 PetscBool ishdf5; 735 736 PetscFunctionBegin; 737 PetscCall(VecGetDM(v, &dm)); 738 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 739 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 740 if (ishdf5) { 741 DM dmBC; 742 Vec gv; 743 const char *name; 744 745 PetscCall(DMGetOutputDM(dm, &dmBC)); 746 PetscCall(DMGetGlobalVector(dmBC, &gv)); 747 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 748 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 749 PetscCall(VecLoad_Default(gv, viewer)); 750 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 751 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 753 } else PetscCall(VecLoad_Default(v, viewer)); 754 PetscFunctionReturn(PETSC_SUCCESS); 755 } 756 757 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 758 { 759 DM dm; 760 PetscBool ishdf5, isexodusii; 761 762 PetscFunctionBegin; 763 PetscCall(VecGetDM(v, &dm)); 764 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 765 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 767 if (ishdf5) { 768 #if defined(PETSC_HAVE_HDF5) 769 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 770 #else 771 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 772 #endif 773 } else if (isexodusii) { 774 #if defined(PETSC_HAVE_EXODUSII) 775 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 776 #else 777 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 778 #endif 779 } else PetscCall(VecLoad_Default(v, viewer)); 780 PetscFunctionReturn(PETSC_SUCCESS); 781 } 782 783 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 784 { 785 DM dm; 786 PetscViewerFormat format; 787 PetscBool ishdf5; 788 789 PetscFunctionBegin; 790 PetscCall(VecGetDM(originalv, &dm)); 791 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 792 PetscCall(PetscViewerGetFormat(viewer, &format)); 793 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 794 if (format == PETSC_VIEWER_NATIVE) { 795 if (dm->useNatural) { 796 if (dm->sfNatural) { 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 Vec v; 800 const char *vecname; 801 802 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 803 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 804 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 805 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 806 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 807 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 808 PetscCall(VecDestroy(&v)); 809 #else 810 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 811 #endif 812 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 813 } 814 } else PetscCall(VecLoad_Default(originalv, viewer)); 815 } 816 PetscFunctionReturn(PETSC_SUCCESS); 817 } 818 819 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 820 { 821 PetscSection coordSection; 822 Vec coordinates; 823 DMLabel depthLabel, celltypeLabel; 824 const char *name[4]; 825 const PetscScalar *a; 826 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 827 828 PetscFunctionBegin; 829 PetscCall(DMGetDimension(dm, &dim)); 830 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 831 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 832 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 833 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 834 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 835 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 836 PetscCall(VecGetArrayRead(coordinates, &a)); 837 name[0] = "vertex"; 838 name[1] = "edge"; 839 name[dim - 1] = "face"; 840 name[dim] = "cell"; 841 for (c = cStart; c < cEnd; ++c) { 842 PetscInt *closure = NULL; 843 PetscInt closureSize, cl, ct; 844 845 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 846 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 847 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 848 PetscCall(PetscViewerASCIIPushTab(viewer)); 849 for (cl = 0; cl < closureSize * 2; cl += 2) { 850 PetscInt point = closure[cl], depth, dof, off, d, p; 851 852 if ((point < pStart) || (point >= pEnd)) continue; 853 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 854 if (!dof) continue; 855 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 856 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 858 for (p = 0; p < dof / dim; ++p) { 859 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 860 for (d = 0; d < dim; ++d) { 861 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 862 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 863 } 864 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 865 } 866 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 867 } 868 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 869 PetscCall(PetscViewerASCIIPopTab(viewer)); 870 } 871 PetscCall(VecRestoreArrayRead(coordinates, &a)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 typedef enum { 876 CS_CARTESIAN, 877 CS_POLAR, 878 CS_CYLINDRICAL, 879 CS_SPHERICAL 880 } CoordSystem; 881 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 882 883 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 884 { 885 PetscInt i; 886 887 PetscFunctionBegin; 888 if (dim > 3) { 889 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 890 } else { 891 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 892 893 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 894 switch (cs) { 895 case CS_CARTESIAN: 896 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 897 break; 898 case CS_POLAR: 899 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 900 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 901 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 902 break; 903 case CS_CYLINDRICAL: 904 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 905 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 906 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 907 trcoords[2] = coords[2]; 908 break; 909 case CS_SPHERICAL: 910 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 911 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 912 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 913 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 914 break; 915 } 916 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 917 } 918 PetscFunctionReturn(PETSC_SUCCESS); 919 } 920 921 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 922 { 923 DM_Plex *mesh = (DM_Plex *)dm->data; 924 DM cdm, cdmCell; 925 PetscSection coordSection, coordSectionCell; 926 Vec coordinates, coordinatesCell; 927 PetscViewerFormat format; 928 929 PetscFunctionBegin; 930 PetscCall(PetscViewerGetFormat(viewer, &format)); 931 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 932 const char *name; 933 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 934 PetscInt pStart, pEnd, p, numLabels, l; 935 PetscMPIInt rank, size; 936 937 PetscCall(DMGetCoordinateDM(dm, &cdm)); 938 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 939 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 940 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 941 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 942 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 943 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 944 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 945 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 946 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 947 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 948 PetscCall(DMGetDimension(dm, &dim)); 949 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 950 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 951 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 952 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 953 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 954 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 955 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 956 for (p = pStart; p < pEnd; ++p) { 957 PetscInt dof, off, s; 958 959 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 960 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 961 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 962 } 963 PetscCall(PetscViewerFlush(viewer)); 964 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 965 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 966 for (p = pStart; p < pEnd; ++p) { 967 PetscInt dof, off, c; 968 969 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 970 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 971 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])); 972 } 973 PetscCall(PetscViewerFlush(viewer)); 974 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 975 if (coordSection && coordinates) { 976 CoordSystem cs = CS_CARTESIAN; 977 const PetscScalar *array, *arrayCell = NULL; 978 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 979 PetscMPIInt rank; 980 const char *name; 981 982 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 983 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 984 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 985 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 986 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 987 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 988 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 989 pStart = PetscMin(pvStart, pcStart); 990 pEnd = PetscMax(pvEnd, pcEnd); 991 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 992 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 994 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 995 996 PetscCall(VecGetArrayRead(coordinates, &array)); 997 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 998 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 999 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1000 for (p = pStart; p < pEnd; ++p) { 1001 PetscInt dof, off; 1002 1003 if (p >= pvStart && p < pvEnd) { 1004 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1005 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1006 if (dof) { 1007 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1008 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1009 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1010 } 1011 } 1012 if (cdmCell && p >= pcStart && p < pcEnd) { 1013 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1014 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1015 if (dof) { 1016 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1017 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1018 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1019 } 1020 } 1021 } 1022 PetscCall(PetscViewerFlush(viewer)); 1023 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1024 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1025 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1026 } 1027 PetscCall(DMGetNumLabels(dm, &numLabels)); 1028 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1029 for (l = 0; l < numLabels; ++l) { 1030 DMLabel label; 1031 PetscBool isdepth; 1032 const char *name; 1033 1034 PetscCall(DMGetLabelName(dm, l, &name)); 1035 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1036 if (isdepth) continue; 1037 PetscCall(DMGetLabel(dm, name, &label)); 1038 PetscCall(DMLabelView(label, viewer)); 1039 } 1040 if (size > 1) { 1041 PetscSF sf; 1042 1043 PetscCall(DMGetPointSF(dm, &sf)); 1044 PetscCall(PetscSFView(sf, viewer)); 1045 } 1046 if (mesh->periodic.face_sfs) 1047 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], 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, fStart = 0, fEnd = 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 n = 4; 1088 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1089 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1091 if (!useLabels) numLabels = 0; 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1093 if (!useColors) { 1094 numColors = 3; 1095 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1096 } 1097 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1098 if (!useColors) { 1099 numLColors = 4; 1100 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1101 } 1102 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1103 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1104 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1105 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1106 if (depth < dim) plotEdges = PETSC_FALSE; 1107 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1108 1109 /* filter points with labelvalue != labeldefaultvalue */ 1110 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1112 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1114 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1115 if (lflg) { 1116 DMLabel lbl; 1117 1118 PetscCall(DMGetLabel(dm, lname, &lbl)); 1119 if (lbl) { 1120 PetscInt val, defval; 1121 1122 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1123 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1124 for (c = pStart; c < pEnd; c++) { 1125 PetscInt *closure = NULL; 1126 PetscInt closureSize; 1127 1128 PetscCall(DMLabelGetValue(lbl, c, &val)); 1129 if (val == defval) continue; 1130 1131 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1132 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1133 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 } 1135 } 1136 } 1137 1138 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1139 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1140 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1141 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1142 \\documentclass[tikz]{standalone}\n\n\ 1143 \\usepackage{pgflibraryshapes}\n\ 1144 \\usetikzlibrary{backgrounds}\n\ 1145 \\usetikzlibrary{arrows}\n\ 1146 \\begin{document}\n")); 1147 if (size > 1) { 1148 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1149 for (p = 0; p < size; ++p) { 1150 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1151 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1152 } 1153 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1154 } 1155 if (drawHasse) { 1156 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1157 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1171 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1172 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1173 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1174 } 1175 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1176 1177 /* Plot vertices */ 1178 PetscCall(VecGetArray(coordinates, &coords)); 1179 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1180 for (v = vStart; v < vEnd; ++v) { 1181 PetscInt off, dof, d; 1182 PetscBool isLabeled = PETSC_FALSE; 1183 1184 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1185 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1186 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1187 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1188 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1189 for (d = 0; d < dof; ++d) { 1190 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1191 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1192 } 1193 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1194 if (dim == 3) { 1195 PetscReal tmp = tcoords[1]; 1196 tcoords[1] = tcoords[2]; 1197 tcoords[2] = -tmp; 1198 } 1199 for (d = 0; d < dof; ++d) { 1200 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1201 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1202 } 1203 if (drawHasse) color = colors[0 % numColors]; 1204 else color = colors[rank % numColors]; 1205 for (l = 0; l < numLabels; ++l) { 1206 PetscInt val; 1207 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1208 if (val >= 0) { 1209 color = lcolors[l % numLColors]; 1210 isLabeled = PETSC_TRUE; 1211 break; 1212 } 1213 } 1214 if (drawNumbers[0]) { 1215 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1216 } else if (drawColors[0]) { 1217 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1218 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1219 } 1220 PetscCall(VecRestoreArray(coordinates, &coords)); 1221 PetscCall(PetscViewerFlush(viewer)); 1222 /* Plot edges */ 1223 if (plotEdges) { 1224 PetscCall(VecGetArray(coordinates, &coords)); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1226 for (e = eStart; e < eEnd; ++e) { 1227 const PetscInt *cone; 1228 PetscInt coneSize, offA, offB, dof, d; 1229 1230 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1231 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1232 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1233 PetscCall(DMPlexGetCone(dm, e, &cone)); 1234 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1235 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1236 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1237 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1238 for (d = 0; d < dof; ++d) { 1239 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1240 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1241 } 1242 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1243 if (dim == 3) { 1244 PetscReal tmp = tcoords[1]; 1245 tcoords[1] = tcoords[2]; 1246 tcoords[2] = -tmp; 1247 } 1248 for (d = 0; d < dof; ++d) { 1249 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1250 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1251 } 1252 if (drawHasse) color = colors[1 % numColors]; 1253 else color = colors[rank % numColors]; 1254 for (l = 0; l < numLabels; ++l) { 1255 PetscInt val; 1256 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1257 if (val >= 0) { 1258 color = lcolors[l % numLColors]; 1259 break; 1260 } 1261 } 1262 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1263 } 1264 PetscCall(VecRestoreArray(coordinates, &coords)); 1265 PetscCall(PetscViewerFlush(viewer)); 1266 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1267 } 1268 /* Plot cells */ 1269 if (dim == 3 || !drawNumbers[1]) { 1270 for (e = eStart; e < eEnd; ++e) { 1271 const PetscInt *cone; 1272 1273 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1274 color = colors[rank % numColors]; 1275 for (l = 0; l < numLabels; ++l) { 1276 PetscInt val; 1277 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1278 if (val >= 0) { 1279 color = lcolors[l % numLColors]; 1280 break; 1281 } 1282 } 1283 PetscCall(DMPlexGetCone(dm, e, &cone)); 1284 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1285 } 1286 } else { 1287 DMPolytopeType ct; 1288 1289 /* Drawing a 2D polygon */ 1290 for (c = cStart; c < cEnd; ++c) { 1291 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1292 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1293 if (DMPolytopeTypeIsHybrid(ct)) { 1294 const PetscInt *cone; 1295 PetscInt coneSize, e; 1296 1297 PetscCall(DMPlexGetCone(dm, c, &cone)); 1298 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1299 for (e = 0; e < coneSize; ++e) { 1300 const PetscInt *econe; 1301 1302 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1303 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)); 1304 } 1305 } else { 1306 PetscInt *closure = NULL; 1307 PetscInt closureSize, Nv = 0, v; 1308 1309 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1310 for (p = 0; p < closureSize * 2; p += 2) { 1311 const PetscInt point = closure[p]; 1312 1313 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1314 } 1315 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1316 for (v = 0; v <= Nv; ++v) { 1317 const PetscInt vertex = closure[v % Nv]; 1318 1319 if (v > 0) { 1320 if (plotEdges) { 1321 const PetscInt *edge; 1322 PetscInt endpoints[2], ne; 1323 1324 endpoints[0] = closure[v - 1]; 1325 endpoints[1] = vertex; 1326 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1327 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1328 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1329 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1330 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1331 } 1332 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1333 } 1334 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1335 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1336 } 1337 } 1338 } 1339 for (c = cStart; c < cEnd; ++c) { 1340 double ccoords[3] = {0.0, 0.0, 0.0}; 1341 PetscBool isLabeled = PETSC_FALSE; 1342 PetscScalar *cellCoords = NULL; 1343 const PetscScalar *array; 1344 PetscInt numCoords, cdim, d; 1345 PetscBool isDG; 1346 1347 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1348 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1349 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1350 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1351 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1352 for (p = 0; p < numCoords / cdim; ++p) { 1353 for (d = 0; d < cdim; ++d) { 1354 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1355 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1356 } 1357 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1358 if (cdim == 3) { 1359 PetscReal tmp = tcoords[1]; 1360 tcoords[1] = tcoords[2]; 1361 tcoords[2] = -tmp; 1362 } 1363 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1364 } 1365 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1366 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1367 for (d = 0; d < cdim; ++d) { 1368 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1369 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1370 } 1371 if (drawHasse) color = colors[depth % numColors]; 1372 else color = colors[rank % numColors]; 1373 for (l = 0; l < numLabels; ++l) { 1374 PetscInt val; 1375 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1376 if (val >= 0) { 1377 color = lcolors[l % numLColors]; 1378 isLabeled = PETSC_TRUE; 1379 break; 1380 } 1381 } 1382 if (drawNumbers[dim]) { 1383 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1384 } else if (drawColors[dim]) { 1385 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1386 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1387 } 1388 if (drawHasse) { 1389 int height = 0; 1390 1391 color = colors[depth % numColors]; 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1397 1398 if (depth > 2) { 1399 color = colors[1 % numColors]; 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1404 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1405 } 1406 1407 color = colors[1 % numColors]; 1408 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1409 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1410 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1411 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1412 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1413 1414 color = colors[0 % numColors]; 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1420 1421 for (p = pStart; p < pEnd; ++p) { 1422 const PetscInt *cone; 1423 PetscInt coneSize, cp; 1424 1425 PetscCall(DMPlexGetCone(dm, p, &cone)); 1426 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1427 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1428 } 1429 } 1430 PetscCall(PetscViewerFlush(viewer)); 1431 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1432 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1433 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1434 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1435 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1436 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1437 PetscCall(PetscFree3(names, colors, lcolors)); 1438 PetscCall(PetscBTDestroy(&wp)); 1439 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1440 Vec cown, acown; 1441 VecScatter sct; 1442 ISLocalToGlobalMapping g2l; 1443 IS gid, acis; 1444 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1445 MPI_Group ggroup, ngroup; 1446 PetscScalar *array, nid; 1447 const PetscInt *idxs; 1448 PetscInt *idxs2, *start, *adjacency, *work; 1449 PetscInt64 lm[3], gm[3]; 1450 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1451 PetscMPIInt d1, d2, rank; 1452 1453 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1454 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1455 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1456 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1457 #endif 1458 if (ncomm != MPI_COMM_NULL) { 1459 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1460 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1461 d1 = 0; 1462 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1463 nid = d2; 1464 PetscCallMPI(MPI_Group_free(&ggroup)); 1465 PetscCallMPI(MPI_Group_free(&ngroup)); 1466 PetscCallMPI(MPI_Comm_free(&ncomm)); 1467 } else nid = 0.0; 1468 1469 /* Get connectivity */ 1470 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1471 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1472 1473 /* filter overlapped local cells */ 1474 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1475 PetscCall(ISGetIndices(gid, &idxs)); 1476 PetscCall(ISGetLocalSize(gid, &cum)); 1477 PetscCall(PetscMalloc1(cum, &idxs2)); 1478 for (c = cStart, cum = 0; c < cEnd; c++) { 1479 if (idxs[c - cStart] < 0) continue; 1480 idxs2[cum++] = idxs[c - cStart]; 1481 } 1482 PetscCall(ISRestoreIndices(gid, &idxs)); 1483 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1484 PetscCall(ISDestroy(&gid)); 1485 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1486 1487 /* support for node-aware cell locality */ 1488 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1489 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1490 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1491 PetscCall(VecGetArray(cown, &array)); 1492 for (c = 0; c < numVertices; c++) array[c] = nid; 1493 PetscCall(VecRestoreArray(cown, &array)); 1494 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1495 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1496 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1497 PetscCall(ISDestroy(&acis)); 1498 PetscCall(VecScatterDestroy(&sct)); 1499 PetscCall(VecDestroy(&cown)); 1500 1501 /* compute edgeCut */ 1502 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1503 PetscCall(PetscMalloc1(cum, &work)); 1504 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1505 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1506 PetscCall(ISDestroy(&gid)); 1507 PetscCall(VecGetArray(acown, &array)); 1508 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1509 PetscInt totl; 1510 1511 totl = start[c + 1] - start[c]; 1512 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1513 for (i = 0; i < totl; i++) { 1514 if (work[i] < 0) { 1515 ect += 1; 1516 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1517 } 1518 } 1519 } 1520 PetscCall(PetscFree(work)); 1521 PetscCall(VecRestoreArray(acown, &array)); 1522 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1523 lm[1] = -numVertices; 1524 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1526 lm[0] = ect; /* edgeCut */ 1527 lm[1] = ectn; /* node-aware edgeCut */ 1528 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1529 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1530 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1531 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1532 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1533 #else 1534 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1535 #endif 1536 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1537 PetscCall(PetscFree(start)); 1538 PetscCall(PetscFree(adjacency)); 1539 PetscCall(VecDestroy(&acown)); 1540 } else { 1541 const char *name; 1542 PetscInt *sizes, *hybsizes, *ghostsizes; 1543 PetscInt locDepth, depth, cellHeight, dim, d; 1544 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1545 PetscInt numLabels, l, maxSize = 17; 1546 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1547 MPI_Comm comm; 1548 PetscMPIInt size, rank; 1549 1550 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1551 PetscCallMPI(MPI_Comm_size(comm, &size)); 1552 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1553 PetscCall(DMGetDimension(dm, &dim)); 1554 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1555 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1556 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1557 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1558 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1559 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1560 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1561 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1562 gcNum = gcEnd - gcStart; 1563 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1564 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1565 for (d = 0; d <= depth; d++) { 1566 PetscInt Nc[2] = {0, 0}, ict; 1567 1568 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1569 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1570 ict = ct0; 1571 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1572 ct0 = (DMPolytopeType)ict; 1573 for (p = pStart; p < pEnd; ++p) { 1574 DMPolytopeType ct; 1575 1576 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1577 if (ct == ct0) ++Nc[0]; 1578 else ++Nc[1]; 1579 } 1580 if (size < maxSize) { 1581 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1582 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1583 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1584 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1585 for (p = 0; p < size; ++p) { 1586 if (rank == 0) { 1587 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1588 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1589 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1590 } 1591 } 1592 } else { 1593 PetscInt locMinMax[2]; 1594 1595 locMinMax[0] = Nc[0] + Nc[1]; 1596 locMinMax[1] = Nc[0] + Nc[1]; 1597 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1598 locMinMax[0] = Nc[1]; 1599 locMinMax[1] = Nc[1]; 1600 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1601 if (d == depth) { 1602 locMinMax[0] = gcNum; 1603 locMinMax[1] = gcNum; 1604 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1605 } 1606 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1607 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1608 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1609 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1610 } 1611 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1612 } 1613 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1614 { 1615 const PetscReal *maxCell; 1616 const PetscReal *L; 1617 PetscBool localized; 1618 1619 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1620 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1621 if (L || localized) { 1622 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1623 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1624 if (L) { 1625 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1626 for (d = 0; d < dim; ++d) { 1627 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1628 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1629 } 1630 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1631 } 1632 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1633 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1634 } 1635 } 1636 PetscCall(DMGetNumLabels(dm, &numLabels)); 1637 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1638 for (l = 0; l < numLabels; ++l) { 1639 DMLabel label; 1640 const char *name; 1641 IS valueIS; 1642 const PetscInt *values; 1643 PetscInt numValues, v; 1644 1645 PetscCall(DMGetLabelName(dm, l, &name)); 1646 PetscCall(DMGetLabel(dm, name, &label)); 1647 PetscCall(DMLabelGetNumValues(label, &numValues)); 1648 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1649 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1650 PetscCall(ISGetIndices(valueIS, &values)); 1651 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1652 for (v = 0; v < numValues; ++v) { 1653 PetscInt size; 1654 1655 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1656 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1657 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1658 } 1659 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1660 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1661 PetscCall(ISRestoreIndices(valueIS, &values)); 1662 PetscCall(ISDestroy(&valueIS)); 1663 } 1664 { 1665 char **labelNames; 1666 PetscInt Nl = numLabels; 1667 PetscBool flg; 1668 1669 PetscCall(PetscMalloc1(Nl, &labelNames)); 1670 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1671 for (l = 0; l < Nl; ++l) { 1672 DMLabel label; 1673 1674 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1675 if (flg) { 1676 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1677 PetscCall(DMLabelView(label, viewer)); 1678 } 1679 PetscCall(PetscFree(labelNames[l])); 1680 } 1681 PetscCall(PetscFree(labelNames)); 1682 } 1683 /* If no fields are specified, people do not want to see adjacency */ 1684 if (dm->Nf) { 1685 PetscInt f; 1686 1687 for (f = 0; f < dm->Nf; ++f) { 1688 const char *name; 1689 1690 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1691 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1692 PetscCall(PetscViewerASCIIPushTab(viewer)); 1693 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1694 if (dm->fields[f].adjacency[0]) { 1695 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1696 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1697 } else { 1698 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1699 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1700 } 1701 PetscCall(PetscViewerASCIIPopTab(viewer)); 1702 } 1703 } 1704 PetscCall(DMGetCoarseDM(dm, &cdm)); 1705 if (cdm) { 1706 PetscCall(PetscViewerASCIIPushTab(viewer)); 1707 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1708 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1709 PetscCall(PetscViewerASCIIPopTab(viewer)); 1710 } 1711 } 1712 PetscFunctionReturn(PETSC_SUCCESS); 1713 } 1714 1715 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1716 { 1717 DMPolytopeType ct; 1718 PetscMPIInt rank; 1719 PetscInt cdim; 1720 1721 PetscFunctionBegin; 1722 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1723 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1724 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1725 switch (ct) { 1726 case DM_POLYTOPE_SEGMENT: 1727 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1728 switch (cdim) { 1729 case 1: { 1730 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1731 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1732 1733 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1734 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1735 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1736 } break; 1737 case 2: { 1738 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1739 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1740 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1741 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[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1744 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)); 1745 } break; 1746 default: 1747 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1748 } 1749 break; 1750 case DM_POLYTOPE_TRIANGLE: 1751 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)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1755 break; 1756 case DM_POLYTOPE_QUADRILATERAL: 1757 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)); 1758 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)); 1759 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1760 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1761 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1762 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1763 break; 1764 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1765 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)); 1766 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)); 1767 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1768 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1769 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1770 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1771 break; 1772 case DM_POLYTOPE_FV_GHOST: 1773 break; 1774 default: 1775 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1776 } 1777 PetscFunctionReturn(PETSC_SUCCESS); 1778 } 1779 1780 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1781 { 1782 PetscReal centroid[2] = {0., 0.}; 1783 PetscMPIInt rank; 1784 PetscInt fillColor; 1785 1786 PetscFunctionBegin; 1787 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1788 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1789 for (PetscInt v = 0; v < Nv; ++v) { 1790 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1791 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1792 } 1793 for (PetscInt e = 0; e < Nv; ++e) { 1794 refCoords[0] = refVertices[e * 2 + 0]; 1795 refCoords[1] = refVertices[e * 2 + 1]; 1796 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1797 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1798 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1799 } 1800 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1801 for (PetscInt d = 0; d < edgeDiv; ++d) { 1802 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)); 1803 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1804 } 1805 } 1806 PetscFunctionReturn(PETSC_SUCCESS); 1807 } 1808 1809 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1810 { 1811 DMPolytopeType ct; 1812 1813 PetscFunctionBegin; 1814 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1815 switch (ct) { 1816 case DM_POLYTOPE_TRIANGLE: { 1817 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1818 1819 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1820 } break; 1821 case DM_POLYTOPE_QUADRILATERAL: { 1822 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1823 1824 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1825 } break; 1826 default: 1827 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1828 } 1829 PetscFunctionReturn(PETSC_SUCCESS); 1830 } 1831 1832 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1833 { 1834 PetscDraw draw; 1835 DM cdm; 1836 PetscSection coordSection; 1837 Vec coordinates; 1838 PetscReal xyl[3], xyr[3]; 1839 PetscReal *refCoords, *edgeCoords; 1840 PetscBool isnull, drawAffine; 1841 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1842 1843 PetscFunctionBegin; 1844 PetscCall(DMGetCoordinateDim(dm, &dim)); 1845 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1846 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1847 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1848 edgeDiv = cDegree + 1; 1849 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1850 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1851 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1852 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1853 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1854 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1855 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1856 1857 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1858 PetscCall(PetscDrawIsNull(draw, &isnull)); 1859 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1860 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1861 1862 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1863 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1864 PetscCall(PetscDrawClear(draw)); 1865 1866 for (c = cStart; c < cEnd; ++c) { 1867 PetscScalar *coords = NULL; 1868 const PetscScalar *coords_arr; 1869 PetscInt numCoords; 1870 PetscBool isDG; 1871 1872 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1873 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1874 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1875 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1876 } 1877 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1878 PetscCall(PetscDrawFlush(draw)); 1879 PetscCall(PetscDrawPause(draw)); 1880 PetscCall(PetscDrawSave(draw)); 1881 PetscFunctionReturn(PETSC_SUCCESS); 1882 } 1883 1884 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1885 { 1886 DM odm = dm, rdm = dm, cdm; 1887 PetscFE fe; 1888 PetscSpace sp; 1889 PetscClassId id; 1890 PetscInt degree; 1891 PetscBool hoView = PETSC_TRUE; 1892 1893 PetscFunctionBegin; 1894 PetscObjectOptionsBegin((PetscObject)dm); 1895 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1896 PetscOptionsEnd(); 1897 PetscCall(PetscObjectReference((PetscObject)dm)); 1898 *hdm = dm; 1899 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1900 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1901 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1902 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1903 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1904 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1905 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1906 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1907 DM cdm, rcdm; 1908 Mat In; 1909 Vec cl, rcl; 1910 1911 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1912 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1913 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1914 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1915 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1916 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1917 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1918 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1919 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1920 PetscCall(MatMult(In, cl, rcl)); 1921 PetscCall(MatDestroy(&In)); 1922 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1923 PetscCall(DMDestroy(&odm)); 1924 odm = rdm; 1925 } 1926 *hdm = rdm; 1927 PetscFunctionReturn(PETSC_SUCCESS); 1928 } 1929 1930 #if defined(PETSC_HAVE_EXODUSII) 1931 #include <exodusII.h> 1932 #include <petscviewerexodusii.h> 1933 #endif 1934 1935 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1936 { 1937 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1938 char name[PETSC_MAX_PATH_LEN]; 1939 1940 PetscFunctionBegin; 1941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1942 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1943 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1944 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1945 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1946 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1947 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1948 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1949 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1950 if (iascii) { 1951 PetscViewerFormat format; 1952 PetscCall(PetscViewerGetFormat(viewer, &format)); 1953 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1954 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1955 } else if (ishdf5) { 1956 #if defined(PETSC_HAVE_HDF5) 1957 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1958 #else 1959 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1960 #endif 1961 } else if (isvtk) { 1962 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1963 } else if (isdraw) { 1964 DM hdm; 1965 1966 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1967 PetscCall(DMPlexView_Draw(hdm, viewer)); 1968 PetscCall(DMDestroy(&hdm)); 1969 } else if (isglvis) { 1970 PetscCall(DMPlexView_GLVis(dm, viewer)); 1971 #if defined(PETSC_HAVE_EXODUSII) 1972 } else if (isexodus) { 1973 /* 1974 exodusII requires that all sets be part of exactly one cell set. 1975 If the dm does not have a "Cell Sets" label defined, we create one 1976 with ID 1, containing all cells. 1977 Note that if the Cell Sets label is defined but does not cover all cells, 1978 we may still have a problem. This should probably be checked here or in the viewer; 1979 */ 1980 PetscInt numCS; 1981 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1982 if (!numCS) { 1983 PetscInt cStart, cEnd, c; 1984 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1985 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1986 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1987 } 1988 PetscCall(DMView_PlexExodusII(dm, viewer)); 1989 #endif 1990 #if defined(PETSC_HAVE_CGNS) 1991 } else if (iscgns) { 1992 PetscCall(DMView_PlexCGNS(dm, viewer)); 1993 #endif 1994 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1995 /* Optionally view the partition */ 1996 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1997 if (flg) { 1998 Vec ranks; 1999 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2000 PetscCall(VecView(ranks, viewer)); 2001 PetscCall(VecDestroy(&ranks)); 2002 } 2003 /* Optionally view a label */ 2004 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2005 if (flg) { 2006 DMLabel label; 2007 Vec val; 2008 2009 PetscCall(DMGetLabel(dm, name, &label)); 2010 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2011 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2012 PetscCall(VecView(val, viewer)); 2013 PetscCall(VecDestroy(&val)); 2014 } 2015 PetscFunctionReturn(PETSC_SUCCESS); 2016 } 2017 2018 /*@ 2019 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2020 2021 Collective 2022 2023 Input Parameters: 2024 + dm - The `DM` whose topology is to be saved 2025 - viewer - The `PetscViewer` to save it in 2026 2027 Level: advanced 2028 2029 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2030 @*/ 2031 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2032 { 2033 PetscBool ishdf5; 2034 2035 PetscFunctionBegin; 2036 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2037 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2038 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2039 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2040 if (ishdf5) { 2041 #if defined(PETSC_HAVE_HDF5) 2042 PetscViewerFormat format; 2043 PetscCall(PetscViewerGetFormat(viewer, &format)); 2044 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2045 IS globalPointNumbering; 2046 2047 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2048 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2049 PetscCall(ISDestroy(&globalPointNumbering)); 2050 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2051 #else 2052 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2053 #endif 2054 } 2055 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2056 PetscFunctionReturn(PETSC_SUCCESS); 2057 } 2058 2059 /*@ 2060 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2061 2062 Collective 2063 2064 Input Parameters: 2065 + dm - The `DM` whose coordinates are to be saved 2066 - viewer - The `PetscViewer` for saving 2067 2068 Level: advanced 2069 2070 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2071 @*/ 2072 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2073 { 2074 PetscBool ishdf5; 2075 2076 PetscFunctionBegin; 2077 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2078 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2079 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2080 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2081 if (ishdf5) { 2082 #if defined(PETSC_HAVE_HDF5) 2083 PetscViewerFormat format; 2084 PetscCall(PetscViewerGetFormat(viewer, &format)); 2085 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2086 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2087 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2088 #else 2089 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2090 #endif 2091 } 2092 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2093 PetscFunctionReturn(PETSC_SUCCESS); 2094 } 2095 2096 /*@ 2097 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2098 2099 Collective 2100 2101 Input Parameters: 2102 + dm - The `DM` whose labels are to be saved 2103 - viewer - The `PetscViewer` for saving 2104 2105 Level: advanced 2106 2107 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2108 @*/ 2109 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2110 { 2111 PetscBool ishdf5; 2112 2113 PetscFunctionBegin; 2114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2115 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2116 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2117 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2118 if (ishdf5) { 2119 #if defined(PETSC_HAVE_HDF5) 2120 IS globalPointNumbering; 2121 PetscViewerFormat format; 2122 2123 PetscCall(PetscViewerGetFormat(viewer, &format)); 2124 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2125 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2126 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2127 PetscCall(ISDestroy(&globalPointNumbering)); 2128 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2129 #else 2130 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2131 #endif 2132 } 2133 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2134 PetscFunctionReturn(PETSC_SUCCESS); 2135 } 2136 2137 /*@ 2138 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2139 2140 Collective 2141 2142 Input Parameters: 2143 + dm - The `DM` that contains the topology on which the section to be saved is defined 2144 . viewer - The `PetscViewer` for saving 2145 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2146 2147 Level: advanced 2148 2149 Notes: 2150 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. 2151 2152 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2153 2154 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2155 @*/ 2156 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2157 { 2158 PetscBool ishdf5; 2159 2160 PetscFunctionBegin; 2161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2162 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2163 if (!sectiondm) sectiondm = dm; 2164 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2165 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2166 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2167 if (ishdf5) { 2168 #if defined(PETSC_HAVE_HDF5) 2169 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2170 #else 2171 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2172 #endif 2173 } 2174 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2175 PetscFunctionReturn(PETSC_SUCCESS); 2176 } 2177 2178 /*@ 2179 DMPlexGlobalVectorView - Saves a global vector 2180 2181 Collective 2182 2183 Input Parameters: 2184 + dm - The `DM` that represents the topology 2185 . viewer - The `PetscViewer` to save data with 2186 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2187 - vec - The global vector to be saved 2188 2189 Level: advanced 2190 2191 Notes: 2192 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2193 2194 Calling sequence: 2195 .vb 2196 DMCreate(PETSC_COMM_WORLD, &dm); 2197 DMSetType(dm, DMPLEX); 2198 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2199 DMClone(dm, §iondm); 2200 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2201 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2202 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2203 PetscSectionSetChart(section, pStart, pEnd); 2204 PetscSectionSetUp(section); 2205 DMSetLocalSection(sectiondm, section); 2206 PetscSectionDestroy(§ion); 2207 DMGetGlobalVector(sectiondm, &vec); 2208 PetscObjectSetName((PetscObject)vec, "vec_name"); 2209 DMPlexTopologyView(dm, viewer); 2210 DMPlexSectionView(dm, viewer, sectiondm); 2211 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2212 DMRestoreGlobalVector(sectiondm, &vec); 2213 DMDestroy(§iondm); 2214 DMDestroy(&dm); 2215 .ve 2216 2217 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2218 @*/ 2219 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2220 { 2221 PetscBool ishdf5; 2222 2223 PetscFunctionBegin; 2224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2225 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2226 if (!sectiondm) sectiondm = dm; 2227 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2228 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2229 /* Check consistency */ 2230 { 2231 PetscSection section; 2232 PetscBool includesConstraints; 2233 PetscInt m, m1; 2234 2235 PetscCall(VecGetLocalSize(vec, &m1)); 2236 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2237 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2238 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2239 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2240 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2241 } 2242 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2243 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2244 if (ishdf5) { 2245 #if defined(PETSC_HAVE_HDF5) 2246 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2247 #else 2248 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2249 #endif 2250 } 2251 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2252 PetscFunctionReturn(PETSC_SUCCESS); 2253 } 2254 2255 /*@ 2256 DMPlexLocalVectorView - Saves a local vector 2257 2258 Collective 2259 2260 Input Parameters: 2261 + dm - The `DM` that represents the topology 2262 . viewer - The `PetscViewer` to save data with 2263 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2264 - vec - The local vector to be saved 2265 2266 Level: advanced 2267 2268 Note: 2269 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2270 2271 Calling sequence: 2272 .vb 2273 DMCreate(PETSC_COMM_WORLD, &dm); 2274 DMSetType(dm, DMPLEX); 2275 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2276 DMClone(dm, §iondm); 2277 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2278 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2279 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2280 PetscSectionSetChart(section, pStart, pEnd); 2281 PetscSectionSetUp(section); 2282 DMSetLocalSection(sectiondm, section); 2283 DMGetLocalVector(sectiondm, &vec); 2284 PetscObjectSetName((PetscObject)vec, "vec_name"); 2285 DMPlexTopologyView(dm, viewer); 2286 DMPlexSectionView(dm, viewer, sectiondm); 2287 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2288 DMRestoreLocalVector(sectiondm, &vec); 2289 DMDestroy(§iondm); 2290 DMDestroy(&dm); 2291 .ve 2292 2293 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2294 @*/ 2295 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2296 { 2297 PetscBool ishdf5; 2298 2299 PetscFunctionBegin; 2300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2301 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2302 if (!sectiondm) sectiondm = dm; 2303 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2304 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2305 /* Check consistency */ 2306 { 2307 PetscSection section; 2308 PetscBool includesConstraints; 2309 PetscInt m, m1; 2310 2311 PetscCall(VecGetLocalSize(vec, &m1)); 2312 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2313 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2314 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2315 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2316 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2317 } 2318 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2319 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2320 if (ishdf5) { 2321 #if defined(PETSC_HAVE_HDF5) 2322 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2323 #else 2324 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2325 #endif 2326 } 2327 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2328 PetscFunctionReturn(PETSC_SUCCESS); 2329 } 2330 2331 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2332 { 2333 PetscBool ishdf5; 2334 2335 PetscFunctionBegin; 2336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2337 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2338 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2339 if (ishdf5) { 2340 #if defined(PETSC_HAVE_HDF5) 2341 PetscViewerFormat format; 2342 PetscCall(PetscViewerGetFormat(viewer, &format)); 2343 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2344 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2345 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2346 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2347 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2348 PetscFunctionReturn(PETSC_SUCCESS); 2349 #else 2350 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2351 #endif 2352 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2353 } 2354 2355 /*@ 2356 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2357 2358 Collective 2359 2360 Input Parameters: 2361 + dm - The `DM` into which the topology is loaded 2362 - viewer - The `PetscViewer` for the saved topology 2363 2364 Output Parameter: 2365 . 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 2366 2367 Level: advanced 2368 2369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2370 `PetscViewer`, `PetscSF` 2371 @*/ 2372 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2373 { 2374 PetscBool ishdf5; 2375 2376 PetscFunctionBegin; 2377 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2378 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2379 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2380 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2381 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2382 if (ishdf5) { 2383 #if defined(PETSC_HAVE_HDF5) 2384 PetscViewerFormat format; 2385 PetscCall(PetscViewerGetFormat(viewer, &format)); 2386 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2387 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2388 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2389 #else 2390 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2391 #endif 2392 } 2393 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2394 PetscFunctionReturn(PETSC_SUCCESS); 2395 } 2396 2397 /*@ 2398 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2399 2400 Collective 2401 2402 Input Parameters: 2403 + dm - The `DM` into which the coordinates are loaded 2404 . viewer - The `PetscViewer` for the saved coordinates 2405 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2406 2407 Level: advanced 2408 2409 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2410 `PetscSF`, `PetscViewer` 2411 @*/ 2412 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2413 { 2414 PetscBool ishdf5; 2415 2416 PetscFunctionBegin; 2417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2418 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2419 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2420 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2421 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2422 if (ishdf5) { 2423 #if defined(PETSC_HAVE_HDF5) 2424 PetscViewerFormat format; 2425 PetscCall(PetscViewerGetFormat(viewer, &format)); 2426 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2427 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2428 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2429 #else 2430 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2431 #endif 2432 } 2433 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2434 PetscFunctionReturn(PETSC_SUCCESS); 2435 } 2436 2437 /*@ 2438 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2439 2440 Collective 2441 2442 Input Parameters: 2443 + dm - The `DM` into which the labels are loaded 2444 . viewer - The `PetscViewer` for the saved labels 2445 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2446 2447 Level: advanced 2448 2449 Note: 2450 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2451 2452 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2453 `PetscSF`, `PetscViewer` 2454 @*/ 2455 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2456 { 2457 PetscBool ishdf5; 2458 2459 PetscFunctionBegin; 2460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2461 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2462 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2463 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2464 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2465 if (ishdf5) { 2466 #if defined(PETSC_HAVE_HDF5) 2467 PetscViewerFormat format; 2468 2469 PetscCall(PetscViewerGetFormat(viewer, &format)); 2470 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2471 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2472 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2473 #else 2474 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2475 #endif 2476 } 2477 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2478 PetscFunctionReturn(PETSC_SUCCESS); 2479 } 2480 2481 /*@ 2482 DMPlexSectionLoad - Loads section into a `DMPLEX` 2483 2484 Collective 2485 2486 Input Parameters: 2487 + dm - The `DM` that represents the topology 2488 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2489 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2490 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2491 2492 Output Parameters: 2493 + 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) 2494 - 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) 2495 2496 Level: advanced 2497 2498 Notes: 2499 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. 2500 2501 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2502 2503 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. 2504 2505 Example using 2 processes: 2506 .vb 2507 NX (number of points on dm): 4 2508 sectionA : the on-disk section 2509 vecA : a vector associated with sectionA 2510 sectionB : sectiondm's local section constructed in this function 2511 vecB (local) : a vector associated with sectiondm's local section 2512 vecB (global) : a vector associated with sectiondm's global section 2513 2514 rank 0 rank 1 2515 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2516 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2517 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2518 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2519 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2520 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2521 sectionB->atlasDof : 1 0 1 | 1 3 2522 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2523 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2524 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2525 .ve 2526 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2527 2528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2529 @*/ 2530 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2531 { 2532 PetscBool ishdf5; 2533 2534 PetscFunctionBegin; 2535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2536 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2537 if (!sectiondm) sectiondm = dm; 2538 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2539 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2540 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2541 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2542 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2543 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2544 if (ishdf5) { 2545 #if defined(PETSC_HAVE_HDF5) 2546 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2547 #else 2548 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2549 #endif 2550 } 2551 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2552 PetscFunctionReturn(PETSC_SUCCESS); 2553 } 2554 2555 /*@ 2556 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2557 2558 Collective 2559 2560 Input Parameters: 2561 + dm - The `DM` that represents the topology 2562 . viewer - The `PetscViewer` that represents the on-disk vector data 2563 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2564 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2565 - vec - The global vector to set values of 2566 2567 Level: advanced 2568 2569 Notes: 2570 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2571 2572 Calling sequence: 2573 .vb 2574 DMCreate(PETSC_COMM_WORLD, &dm); 2575 DMSetType(dm, DMPLEX); 2576 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2577 DMPlexTopologyLoad(dm, viewer, &sfX); 2578 DMClone(dm, §iondm); 2579 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2580 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2581 DMGetGlobalVector(sectiondm, &vec); 2582 PetscObjectSetName((PetscObject)vec, "vec_name"); 2583 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2584 DMRestoreGlobalVector(sectiondm, &vec); 2585 PetscSFDestroy(&gsf); 2586 PetscSFDestroy(&sfX); 2587 DMDestroy(§iondm); 2588 DMDestroy(&dm); 2589 .ve 2590 2591 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2592 `PetscSF`, `PetscViewer` 2593 @*/ 2594 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2595 { 2596 PetscBool ishdf5; 2597 2598 PetscFunctionBegin; 2599 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2600 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2601 if (!sectiondm) sectiondm = dm; 2602 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2603 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2604 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2605 /* Check consistency */ 2606 { 2607 PetscSection section; 2608 PetscBool includesConstraints; 2609 PetscInt m, m1; 2610 2611 PetscCall(VecGetLocalSize(vec, &m1)); 2612 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2613 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2614 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2615 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2616 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2617 } 2618 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2619 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2620 if (ishdf5) { 2621 #if defined(PETSC_HAVE_HDF5) 2622 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2623 #else 2624 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2625 #endif 2626 } 2627 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2628 PetscFunctionReturn(PETSC_SUCCESS); 2629 } 2630 2631 /*@ 2632 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2633 2634 Collective 2635 2636 Input Parameters: 2637 + dm - The `DM` that represents the topology 2638 . viewer - The `PetscViewer` that represents the on-disk vector data 2639 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2640 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2641 - vec - The local vector to set values of 2642 2643 Level: advanced 2644 2645 Notes: 2646 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2647 2648 Calling sequence: 2649 .vb 2650 DMCreate(PETSC_COMM_WORLD, &dm); 2651 DMSetType(dm, DMPLEX); 2652 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2653 DMPlexTopologyLoad(dm, viewer, &sfX); 2654 DMClone(dm, §iondm); 2655 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2656 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2657 DMGetLocalVector(sectiondm, &vec); 2658 PetscObjectSetName((PetscObject)vec, "vec_name"); 2659 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2660 DMRestoreLocalVector(sectiondm, &vec); 2661 PetscSFDestroy(&lsf); 2662 PetscSFDestroy(&sfX); 2663 DMDestroy(§iondm); 2664 DMDestroy(&dm); 2665 .ve 2666 2667 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2668 `PetscSF`, `PetscViewer` 2669 @*/ 2670 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2671 { 2672 PetscBool ishdf5; 2673 2674 PetscFunctionBegin; 2675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2676 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2677 if (!sectiondm) sectiondm = dm; 2678 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2679 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2680 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2681 /* Check consistency */ 2682 { 2683 PetscSection section; 2684 PetscBool includesConstraints; 2685 PetscInt m, m1; 2686 2687 PetscCall(VecGetLocalSize(vec, &m1)); 2688 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2689 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2690 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2691 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2692 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2693 } 2694 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2695 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2696 if (ishdf5) { 2697 #if defined(PETSC_HAVE_HDF5) 2698 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2699 #else 2700 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2701 #endif 2702 } 2703 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2704 PetscFunctionReturn(PETSC_SUCCESS); 2705 } 2706 2707 PetscErrorCode DMDestroy_Plex(DM dm) 2708 { 2709 DM_Plex *mesh = (DM_Plex *)dm->data; 2710 2711 PetscFunctionBegin; 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2714 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2716 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2717 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2718 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2719 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2720 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2721 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2722 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2723 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2724 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2725 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2726 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2727 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2728 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2729 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2730 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2731 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2732 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2733 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2734 PetscCall(PetscFree(mesh->cones)); 2735 PetscCall(PetscFree(mesh->coneOrientations)); 2736 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2737 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2738 PetscCall(PetscFree(mesh->supports)); 2739 PetscCall(PetscFree(mesh->cellTypes)); 2740 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2741 PetscCall(PetscFree(mesh->tetgenOpts)); 2742 PetscCall(PetscFree(mesh->triangleOpts)); 2743 PetscCall(PetscFree(mesh->transformType)); 2744 PetscCall(PetscFree(mesh->distributionName)); 2745 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2746 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2747 PetscCall(ISDestroy(&mesh->subpointIS)); 2748 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2749 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2750 if (mesh->periodic.face_sfs) { 2751 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2752 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2753 } 2754 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2755 if (mesh->periodic.periodic_points) { 2756 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2757 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2758 } 2759 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2760 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2761 PetscCall(ISDestroy(&mesh->anchorIS)); 2762 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2763 PetscCall(PetscFree(mesh->parents)); 2764 PetscCall(PetscFree(mesh->childIDs)); 2765 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2766 PetscCall(PetscFree(mesh->children)); 2767 PetscCall(DMDestroy(&mesh->referenceTree)); 2768 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2769 PetscCall(PetscFree(mesh->neighbors)); 2770 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2771 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2772 PetscCall(PetscFree(mesh)); 2773 PetscFunctionReturn(PETSC_SUCCESS); 2774 } 2775 2776 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2777 { 2778 PetscSection sectionGlobal, sectionLocal; 2779 PetscInt bs = -1, mbs; 2780 PetscInt localSize, localStart = 0; 2781 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2782 MatType mtype; 2783 ISLocalToGlobalMapping ltog; 2784 2785 PetscFunctionBegin; 2786 PetscCall(MatInitializePackage()); 2787 mtype = dm->mattype; 2788 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2789 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2790 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2791 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2792 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2793 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2794 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2795 PetscCall(MatSetType(*J, mtype)); 2796 PetscCall(MatSetFromOptions(*J)); 2797 PetscCall(MatGetBlockSize(*J, &mbs)); 2798 if (mbs > 1) bs = mbs; 2799 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2800 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2801 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2802 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2803 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2804 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2805 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2806 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2807 if (!isShell) { 2808 // There are three states with pblocks, since block starts can have no dofs: 2809 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2810 // TRUE) Block Start: The first entry in a block has been added 2811 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2812 PetscBT blst; 2813 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2814 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2815 const PetscInt *perm = NULL; 2816 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2817 PetscInt pStart, pEnd, dof, cdof, num_fields; 2818 2819 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2820 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2821 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2822 2823 PetscCall(PetscCalloc1(localSize, &pblocks)); 2824 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2825 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2826 // We need to process in the permuted order to get block sizes right 2827 for (PetscInt point = pStart; point < pEnd; ++point) { 2828 const PetscInt p = perm ? perm[point] : point; 2829 2830 switch (dm->blocking_type) { 2831 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2832 PetscInt bdof, offset; 2833 2834 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2835 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2836 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2837 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2838 if (dof > 0) { 2839 // State change 2840 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2841 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2842 2843 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2844 // Signal block concatenation 2845 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2846 } 2847 dof = dof < 0 ? -(dof + 1) : dof; 2848 bdof = cdof && (dof - cdof) ? 1 : dof; 2849 if (dof) { 2850 if (bs < 0) { 2851 bs = bdof; 2852 } else if (bs != bdof) { 2853 bs = 1; 2854 } 2855 } 2856 } break; 2857 case DM_BLOCKING_FIELD_NODE: { 2858 for (PetscInt field = 0; field < num_fields; field++) { 2859 PetscInt num_comp, bdof, offset; 2860 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2861 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2862 if (dof < 0) continue; 2863 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2864 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2865 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); 2866 PetscInt num_nodes = dof / num_comp; 2867 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2868 // Handle possibly constant block size (unlikely) 2869 bdof = cdof && (dof - cdof) ? 1 : dof; 2870 if (dof) { 2871 if (bs < 0) { 2872 bs = bdof; 2873 } else if (bs != bdof) { 2874 bs = 1; 2875 } 2876 } 2877 } 2878 } break; 2879 } 2880 } 2881 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2882 /* Must have same blocksize on all procs (some might have no points) */ 2883 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2884 bsLocal[1] = bs; 2885 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2886 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2887 else bs = bsMinMax[0]; 2888 bs = PetscMax(1, bs); 2889 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2890 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2891 PetscCall(MatSetBlockSize(*J, bs)); 2892 PetscCall(MatSetUp(*J)); 2893 } else { 2894 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2895 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2896 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2897 } 2898 if (pblocks) { // Consolidate blocks 2899 PetscInt nblocks = 0; 2900 pblocks[0] = PetscAbs(pblocks[0]); 2901 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2902 if (pblocks[i] == 0) continue; 2903 // Negative block size indicates the blocks should be concatenated 2904 if (pblocks[i] < 0) { 2905 pblocks[i] = -pblocks[i]; 2906 pblocks[nblocks - 1] += pblocks[i]; 2907 } else { 2908 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2909 } 2910 for (PetscInt j = 1; j < pblocks[i]; j++) 2911 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 2912 } 2913 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2914 } 2915 PetscCall(PetscFree(pblocks)); 2916 } 2917 PetscCall(MatSetDM(*J, dm)); 2918 PetscFunctionReturn(PETSC_SUCCESS); 2919 } 2920 2921 /*@ 2922 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2923 2924 Not Collective 2925 2926 Input Parameter: 2927 . dm - The `DMPLEX` 2928 2929 Output Parameter: 2930 . subsection - The subdomain section 2931 2932 Level: developer 2933 2934 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2935 @*/ 2936 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2937 { 2938 DM_Plex *mesh = (DM_Plex *)dm->data; 2939 2940 PetscFunctionBegin; 2941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2942 if (!mesh->subdomainSection) { 2943 PetscSection section; 2944 PetscSF sf; 2945 2946 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2947 PetscCall(DMGetLocalSection(dm, §ion)); 2948 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2949 PetscCall(PetscSFDestroy(&sf)); 2950 } 2951 *subsection = mesh->subdomainSection; 2952 PetscFunctionReturn(PETSC_SUCCESS); 2953 } 2954 2955 /*@ 2956 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2957 2958 Not Collective 2959 2960 Input Parameter: 2961 . dm - The `DMPLEX` 2962 2963 Output Parameters: 2964 + pStart - The first mesh point 2965 - pEnd - The upper bound for mesh points 2966 2967 Level: beginner 2968 2969 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2970 @*/ 2971 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2972 { 2973 DM_Plex *mesh = (DM_Plex *)dm->data; 2974 2975 PetscFunctionBegin; 2976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2977 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2978 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2979 PetscFunctionReturn(PETSC_SUCCESS); 2980 } 2981 2982 /*@ 2983 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2984 2985 Not Collective 2986 2987 Input Parameters: 2988 + dm - The `DMPLEX` 2989 . pStart - The first mesh point 2990 - pEnd - The upper bound for mesh points 2991 2992 Level: beginner 2993 2994 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2995 @*/ 2996 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2997 { 2998 DM_Plex *mesh = (DM_Plex *)dm->data; 2999 3000 PetscFunctionBegin; 3001 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3002 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3003 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3004 PetscCall(PetscFree(mesh->cellTypes)); 3005 PetscFunctionReturn(PETSC_SUCCESS); 3006 } 3007 3008 /*@ 3009 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3010 3011 Not Collective 3012 3013 Input Parameters: 3014 + dm - The `DMPLEX` 3015 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3016 3017 Output Parameter: 3018 . size - The cone size for point `p` 3019 3020 Level: beginner 3021 3022 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3023 @*/ 3024 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3025 { 3026 DM_Plex *mesh = (DM_Plex *)dm->data; 3027 3028 PetscFunctionBegin; 3029 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3030 PetscAssertPointer(size, 3); 3031 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3032 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3033 PetscFunctionReturn(PETSC_SUCCESS); 3034 } 3035 3036 /*@ 3037 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3038 3039 Not Collective 3040 3041 Input Parameters: 3042 + dm - The `DMPLEX` 3043 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3044 - size - The cone size for point `p` 3045 3046 Level: beginner 3047 3048 Note: 3049 This should be called after `DMPlexSetChart()`. 3050 3051 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3052 @*/ 3053 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3054 { 3055 DM_Plex *mesh = (DM_Plex *)dm->data; 3056 3057 PetscFunctionBegin; 3058 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3059 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3060 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3061 PetscFunctionReturn(PETSC_SUCCESS); 3062 } 3063 3064 /*@C 3065 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3066 3067 Not Collective 3068 3069 Input Parameters: 3070 + dm - The `DMPLEX` 3071 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3072 3073 Output Parameter: 3074 . cone - An array of points which are on the in-edges for point `p` 3075 3076 Level: beginner 3077 3078 Fortran Notes: 3079 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3080 `DMPlexRestoreCone()` is not needed/available in C. 3081 3082 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3083 @*/ 3084 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3085 { 3086 DM_Plex *mesh = (DM_Plex *)dm->data; 3087 PetscInt off; 3088 3089 PetscFunctionBegin; 3090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3091 PetscAssertPointer(cone, 3); 3092 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3093 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3094 PetscFunctionReturn(PETSC_SUCCESS); 3095 } 3096 3097 /*@ 3098 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3099 3100 Not Collective 3101 3102 Input Parameters: 3103 + dm - The `DMPLEX` 3104 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3105 3106 Output Parameters: 3107 + pConesSection - `PetscSection` describing the layout of `pCones` 3108 - pCones - An array of points which are on the in-edges for the point set `p` 3109 3110 Level: intermediate 3111 3112 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3113 @*/ 3114 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3115 { 3116 PetscSection cs, newcs; 3117 PetscInt *cones; 3118 PetscInt *newarr = NULL; 3119 PetscInt n; 3120 3121 PetscFunctionBegin; 3122 PetscCall(DMPlexGetCones(dm, &cones)); 3123 PetscCall(DMPlexGetConeSection(dm, &cs)); 3124 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3125 if (pConesSection) *pConesSection = newcs; 3126 if (pCones) { 3127 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3128 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3129 } 3130 PetscFunctionReturn(PETSC_SUCCESS); 3131 } 3132 3133 /*@ 3134 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3135 3136 Not Collective 3137 3138 Input Parameters: 3139 + dm - The `DMPLEX` 3140 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3141 3142 Output Parameter: 3143 . expandedPoints - An array of vertices recursively expanded from input points 3144 3145 Level: advanced 3146 3147 Notes: 3148 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3149 3150 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3151 3152 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3153 `DMPlexGetDepth()`, `IS` 3154 @*/ 3155 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3156 { 3157 IS *expandedPointsAll; 3158 PetscInt depth; 3159 3160 PetscFunctionBegin; 3161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3162 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3163 PetscAssertPointer(expandedPoints, 3); 3164 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3165 *expandedPoints = expandedPointsAll[0]; 3166 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3167 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3168 PetscFunctionReturn(PETSC_SUCCESS); 3169 } 3170 3171 /*@ 3172 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). 3173 3174 Not Collective 3175 3176 Input Parameters: 3177 + dm - The `DMPLEX` 3178 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3179 3180 Output Parameters: 3181 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3182 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3183 - sections - (optional) An array of sections which describe mappings from points to their cone points 3184 3185 Level: advanced 3186 3187 Notes: 3188 Like `DMPlexGetConeTuple()` but recursive. 3189 3190 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. 3191 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3192 3193 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\: 3194 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3195 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3196 3197 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3198 `DMPlexGetDepth()`, `PetscSection`, `IS` 3199 @*/ 3200 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3201 { 3202 const PetscInt *arr0 = NULL, *cone = NULL; 3203 PetscInt *arr = NULL, *newarr = NULL; 3204 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3205 IS *expandedPoints_; 3206 PetscSection *sections_; 3207 3208 PetscFunctionBegin; 3209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3210 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3211 if (depth) PetscAssertPointer(depth, 3); 3212 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3213 if (sections) PetscAssertPointer(sections, 5); 3214 PetscCall(ISGetLocalSize(points, &n)); 3215 PetscCall(ISGetIndices(points, &arr0)); 3216 PetscCall(DMPlexGetDepth(dm, &depth_)); 3217 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3218 PetscCall(PetscCalloc1(depth_, §ions_)); 3219 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3220 for (d = depth_ - 1; d >= 0; d--) { 3221 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3222 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3223 for (i = 0; i < n; i++) { 3224 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3225 if (arr[i] >= start && arr[i] < end) { 3226 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3227 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3228 } else { 3229 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3230 } 3231 } 3232 PetscCall(PetscSectionSetUp(sections_[d])); 3233 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3234 PetscCall(PetscMalloc1(newn, &newarr)); 3235 for (i = 0; i < n; i++) { 3236 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3237 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3238 if (cn > 1) { 3239 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3240 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3241 } else { 3242 newarr[co] = arr[i]; 3243 } 3244 } 3245 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3246 arr = newarr; 3247 n = newn; 3248 } 3249 PetscCall(ISRestoreIndices(points, &arr0)); 3250 *depth = depth_; 3251 if (expandedPoints) *expandedPoints = expandedPoints_; 3252 else { 3253 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3254 PetscCall(PetscFree(expandedPoints_)); 3255 } 3256 if (sections) *sections = sections_; 3257 else { 3258 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3259 PetscCall(PetscFree(sections_)); 3260 } 3261 PetscFunctionReturn(PETSC_SUCCESS); 3262 } 3263 3264 /*@ 3265 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3266 3267 Not Collective 3268 3269 Input Parameters: 3270 + dm - The `DMPLEX` 3271 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3272 3273 Output Parameters: 3274 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3275 . expandedPoints - (optional) An array of recursively expanded cones 3276 - sections - (optional) An array of sections which describe mappings from points to their cone points 3277 3278 Level: advanced 3279 3280 Note: 3281 See `DMPlexGetConeRecursive()` 3282 3283 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3284 `DMPlexGetDepth()`, `IS`, `PetscSection` 3285 @*/ 3286 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3287 { 3288 PetscInt d, depth_; 3289 3290 PetscFunctionBegin; 3291 PetscCall(DMPlexGetDepth(dm, &depth_)); 3292 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3293 if (depth) *depth = 0; 3294 if (expandedPoints) { 3295 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3296 PetscCall(PetscFree(*expandedPoints)); 3297 } 3298 if (sections) { 3299 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3300 PetscCall(PetscFree(*sections)); 3301 } 3302 PetscFunctionReturn(PETSC_SUCCESS); 3303 } 3304 3305 /*@ 3306 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 3307 3308 Not Collective 3309 3310 Input Parameters: 3311 + dm - The `DMPLEX` 3312 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3313 - cone - An array of points which are on the in-edges for point `p` 3314 3315 Level: beginner 3316 3317 Note: 3318 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3319 3320 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3321 @*/ 3322 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3323 { 3324 DM_Plex *mesh = (DM_Plex *)dm->data; 3325 PetscInt dof, off, c; 3326 3327 PetscFunctionBegin; 3328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3329 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3330 if (dof) PetscAssertPointer(cone, 3); 3331 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3332 if (PetscDefined(USE_DEBUG)) { 3333 PetscInt pStart, pEnd; 3334 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3335 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); 3336 for (c = 0; c < dof; ++c) { 3337 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); 3338 mesh->cones[off + c] = cone[c]; 3339 } 3340 } else { 3341 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3342 } 3343 PetscFunctionReturn(PETSC_SUCCESS); 3344 } 3345 3346 /*@C 3347 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3348 3349 Not Collective 3350 3351 Input Parameters: 3352 + dm - The `DMPLEX` 3353 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3354 3355 Output Parameter: 3356 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3357 integer giving the prescription for cone traversal. 3358 3359 Level: beginner 3360 3361 Note: 3362 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3363 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3364 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3365 with the identity. 3366 3367 Fortran Notes: 3368 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3369 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3370 3371 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3372 @*/ 3373 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3374 { 3375 DM_Plex *mesh = (DM_Plex *)dm->data; 3376 PetscInt off; 3377 3378 PetscFunctionBegin; 3379 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3380 if (PetscDefined(USE_DEBUG)) { 3381 PetscInt dof; 3382 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3383 if (dof) PetscAssertPointer(coneOrientation, 3); 3384 } 3385 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3386 3387 *coneOrientation = &mesh->coneOrientations[off]; 3388 PetscFunctionReturn(PETSC_SUCCESS); 3389 } 3390 3391 /*@ 3392 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point 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 - coneOrientation - An array of orientations 3400 3401 Level: beginner 3402 3403 Notes: 3404 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3405 3406 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3407 3408 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3409 @*/ 3410 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3411 { 3412 DM_Plex *mesh = (DM_Plex *)dm->data; 3413 PetscInt pStart, pEnd; 3414 PetscInt dof, off, c; 3415 3416 PetscFunctionBegin; 3417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3418 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3419 if (dof) PetscAssertPointer(coneOrientation, 3); 3420 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3421 if (PetscDefined(USE_DEBUG)) { 3422 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3423 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); 3424 for (c = 0; c < dof; ++c) { 3425 PetscInt cdof, o = coneOrientation[c]; 3426 3427 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3428 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); 3429 mesh->coneOrientations[off + c] = o; 3430 } 3431 } else { 3432 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3433 } 3434 PetscFunctionReturn(PETSC_SUCCESS); 3435 } 3436 3437 /*@ 3438 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3439 3440 Not Collective 3441 3442 Input Parameters: 3443 + dm - The `DMPLEX` 3444 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3445 . conePos - The local index in the cone where the point should be put 3446 - conePoint - The mesh point to insert 3447 3448 Level: beginner 3449 3450 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3451 @*/ 3452 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3453 { 3454 DM_Plex *mesh = (DM_Plex *)dm->data; 3455 PetscInt pStart, pEnd; 3456 PetscInt dof, off; 3457 3458 PetscFunctionBegin; 3459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3460 if (PetscDefined(USE_DEBUG)) { 3461 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3462 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); 3463 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); 3464 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3465 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); 3466 } 3467 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3468 mesh->cones[off + conePos] = conePoint; 3469 PetscFunctionReturn(PETSC_SUCCESS); 3470 } 3471 3472 /*@ 3473 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3474 3475 Not Collective 3476 3477 Input Parameters: 3478 + dm - The `DMPLEX` 3479 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3480 . conePos - The local index in the cone where the point should be put 3481 - coneOrientation - The point orientation to insert 3482 3483 Level: beginner 3484 3485 Note: 3486 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3487 3488 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3489 @*/ 3490 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3491 { 3492 DM_Plex *mesh = (DM_Plex *)dm->data; 3493 PetscInt pStart, pEnd; 3494 PetscInt dof, off; 3495 3496 PetscFunctionBegin; 3497 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3498 if (PetscDefined(USE_DEBUG)) { 3499 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3500 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); 3501 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3502 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); 3503 } 3504 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3505 mesh->coneOrientations[off + conePos] = coneOrientation; 3506 PetscFunctionReturn(PETSC_SUCCESS); 3507 } 3508 3509 /*@C 3510 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3511 3512 Not collective 3513 3514 Input Parameters: 3515 + dm - The DMPlex 3516 - p - The point, which must lie in the chart set with DMPlexSetChart() 3517 3518 Output Parameters: 3519 + cone - An array of points which are on the in-edges for point `p` 3520 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3521 integer giving the prescription for cone traversal. 3522 3523 Level: beginner 3524 3525 Notes: 3526 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3527 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3528 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3529 with the identity. 3530 3531 Fortran Notes: 3532 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3533 `DMPlexRestoreCone()` is not needed/available in C. 3534 3535 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3536 @*/ 3537 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3538 { 3539 DM_Plex *mesh = (DM_Plex *)dm->data; 3540 3541 PetscFunctionBegin; 3542 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3543 if (mesh->tr) { 3544 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3545 } else { 3546 PetscInt off; 3547 if (PetscDefined(USE_DEBUG)) { 3548 PetscInt dof; 3549 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3550 if (dof) { 3551 if (cone) PetscAssertPointer(cone, 3); 3552 if (ornt) PetscAssertPointer(ornt, 4); 3553 } 3554 } 3555 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3556 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3557 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3558 } 3559 PetscFunctionReturn(PETSC_SUCCESS); 3560 } 3561 3562 /*@C 3563 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3564 3565 Not Collective 3566 3567 Input Parameters: 3568 + dm - The DMPlex 3569 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3570 . cone - An array of points which are on the in-edges for point p 3571 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3572 integer giving the prescription for cone traversal. 3573 3574 Level: beginner 3575 3576 Notes: 3577 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3578 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3579 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3580 with the identity. 3581 3582 Fortran Notes: 3583 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3584 `DMPlexRestoreCone()` is not needed/available in C. 3585 3586 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3587 @*/ 3588 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3589 { 3590 DM_Plex *mesh = (DM_Plex *)dm->data; 3591 3592 PetscFunctionBegin; 3593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3594 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3595 PetscFunctionReturn(PETSC_SUCCESS); 3596 } 3597 3598 /*@ 3599 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3600 3601 Not Collective 3602 3603 Input Parameters: 3604 + dm - The `DMPLEX` 3605 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3606 3607 Output Parameter: 3608 . size - The support size for point `p` 3609 3610 Level: beginner 3611 3612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3613 @*/ 3614 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3615 { 3616 DM_Plex *mesh = (DM_Plex *)dm->data; 3617 3618 PetscFunctionBegin; 3619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3620 PetscAssertPointer(size, 3); 3621 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3622 PetscFunctionReturn(PETSC_SUCCESS); 3623 } 3624 3625 /*@ 3626 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3627 3628 Not Collective 3629 3630 Input Parameters: 3631 + dm - The `DMPLEX` 3632 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3633 - size - The support size for point `p` 3634 3635 Level: beginner 3636 3637 Note: 3638 This should be called after `DMPlexSetChart()`. 3639 3640 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3641 @*/ 3642 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3643 { 3644 DM_Plex *mesh = (DM_Plex *)dm->data; 3645 3646 PetscFunctionBegin; 3647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3648 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3649 PetscFunctionReturn(PETSC_SUCCESS); 3650 } 3651 3652 /*@C 3653 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3654 3655 Not Collective 3656 3657 Input Parameters: 3658 + dm - The `DMPLEX` 3659 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3660 3661 Output Parameter: 3662 . support - An array of points which are on the out-edges for point `p` 3663 3664 Level: beginner 3665 3666 Fortran Notes: 3667 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3668 `DMPlexRestoreSupport()` is not needed/available in C. 3669 3670 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3671 @*/ 3672 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3673 { 3674 DM_Plex *mesh = (DM_Plex *)dm->data; 3675 PetscInt off; 3676 3677 PetscFunctionBegin; 3678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3679 PetscAssertPointer(support, 3); 3680 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3681 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3682 PetscFunctionReturn(PETSC_SUCCESS); 3683 } 3684 3685 /*@ 3686 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3687 3688 Not Collective 3689 3690 Input Parameters: 3691 + dm - The `DMPLEX` 3692 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3693 - support - An array of points which are on the out-edges for point `p` 3694 3695 Level: beginner 3696 3697 Note: 3698 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3699 3700 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3701 @*/ 3702 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3703 { 3704 DM_Plex *mesh = (DM_Plex *)dm->data; 3705 PetscInt pStart, pEnd; 3706 PetscInt dof, off, c; 3707 3708 PetscFunctionBegin; 3709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3710 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3711 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3712 if (dof) PetscAssertPointer(support, 3); 3713 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3714 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); 3715 for (c = 0; c < dof; ++c) { 3716 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); 3717 mesh->supports[off + c] = support[c]; 3718 } 3719 PetscFunctionReturn(PETSC_SUCCESS); 3720 } 3721 3722 /*@ 3723 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3724 3725 Not Collective 3726 3727 Input Parameters: 3728 + dm - The `DMPLEX` 3729 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3730 . supportPos - The local index in the cone where the point should be put 3731 - supportPoint - The mesh point to insert 3732 3733 Level: beginner 3734 3735 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3736 @*/ 3737 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3738 { 3739 DM_Plex *mesh = (DM_Plex *)dm->data; 3740 PetscInt pStart, pEnd; 3741 PetscInt dof, off; 3742 3743 PetscFunctionBegin; 3744 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3745 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3746 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3747 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3748 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); 3749 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); 3750 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); 3751 mesh->supports[off + supportPos] = supportPoint; 3752 PetscFunctionReturn(PETSC_SUCCESS); 3753 } 3754 3755 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3756 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3757 { 3758 switch (ct) { 3759 case DM_POLYTOPE_SEGMENT: 3760 if (o == -1) return -2; 3761 break; 3762 case DM_POLYTOPE_TRIANGLE: 3763 if (o == -3) return -1; 3764 if (o == -2) return -3; 3765 if (o == -1) return -2; 3766 break; 3767 case DM_POLYTOPE_QUADRILATERAL: 3768 if (o == -4) return -2; 3769 if (o == -3) return -1; 3770 if (o == -2) return -4; 3771 if (o == -1) return -3; 3772 break; 3773 default: 3774 return o; 3775 } 3776 return o; 3777 } 3778 3779 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3780 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3781 { 3782 switch (ct) { 3783 case DM_POLYTOPE_SEGMENT: 3784 if ((o == -2) || (o == 1)) return -1; 3785 if (o == -1) return 0; 3786 break; 3787 case DM_POLYTOPE_TRIANGLE: 3788 if (o == -3) return -2; 3789 if (o == -2) return -1; 3790 if (o == -1) return -3; 3791 break; 3792 case DM_POLYTOPE_QUADRILATERAL: 3793 if (o == -4) return -2; 3794 if (o == -3) return -1; 3795 if (o == -2) return -4; 3796 if (o == -1) return -3; 3797 break; 3798 default: 3799 return o; 3800 } 3801 return o; 3802 } 3803 3804 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3805 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3806 { 3807 PetscInt pStart, pEnd, p; 3808 3809 PetscFunctionBegin; 3810 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3811 for (p = pStart; p < pEnd; ++p) { 3812 const PetscInt *cone, *ornt; 3813 PetscInt coneSize, c; 3814 3815 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3816 PetscCall(DMPlexGetCone(dm, p, &cone)); 3817 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3818 for (c = 0; c < coneSize; ++c) { 3819 DMPolytopeType ct; 3820 const PetscInt o = ornt[c]; 3821 3822 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3823 switch (ct) { 3824 case DM_POLYTOPE_SEGMENT: 3825 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3826 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3827 break; 3828 case DM_POLYTOPE_TRIANGLE: 3829 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3830 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3831 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3832 break; 3833 case DM_POLYTOPE_QUADRILATERAL: 3834 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3835 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3836 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3837 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3838 break; 3839 default: 3840 break; 3841 } 3842 } 3843 } 3844 PetscFunctionReturn(PETSC_SUCCESS); 3845 } 3846 3847 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3848 { 3849 DM_Plex *mesh = (DM_Plex *)dm->data; 3850 3851 PetscFunctionBeginHot; 3852 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3853 if (useCone) { 3854 PetscCall(DMPlexGetConeSize(dm, p, size)); 3855 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3856 } else { 3857 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3858 PetscCall(DMPlexGetSupport(dm, p, arr)); 3859 } 3860 } else { 3861 if (useCone) { 3862 const PetscSection s = mesh->coneSection; 3863 const PetscInt ps = p - s->pStart; 3864 const PetscInt off = s->atlasOff[ps]; 3865 3866 *size = s->atlasDof[ps]; 3867 *arr = mesh->cones + off; 3868 *ornt = mesh->coneOrientations + off; 3869 } else { 3870 const PetscSection s = mesh->supportSection; 3871 const PetscInt ps = p - s->pStart; 3872 const PetscInt off = s->atlasOff[ps]; 3873 3874 *size = s->atlasDof[ps]; 3875 *arr = mesh->supports + off; 3876 } 3877 } 3878 PetscFunctionReturn(PETSC_SUCCESS); 3879 } 3880 3881 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3882 { 3883 DM_Plex *mesh = (DM_Plex *)dm->data; 3884 3885 PetscFunctionBeginHot; 3886 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3887 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3888 } 3889 PetscFunctionReturn(PETSC_SUCCESS); 3890 } 3891 3892 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3893 { 3894 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3895 PetscInt *closure; 3896 const PetscInt *tmp = NULL, *tmpO = NULL; 3897 PetscInt off = 0, tmpSize, t; 3898 3899 PetscFunctionBeginHot; 3900 if (ornt) { 3901 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3902 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; 3903 } 3904 if (*points) { 3905 closure = *points; 3906 } else { 3907 PetscInt maxConeSize, maxSupportSize; 3908 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3909 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3910 } 3911 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3912 if (ct == DM_POLYTOPE_UNKNOWN) { 3913 closure[off++] = p; 3914 closure[off++] = 0; 3915 for (t = 0; t < tmpSize; ++t) { 3916 closure[off++] = tmp[t]; 3917 closure[off++] = tmpO ? tmpO[t] : 0; 3918 } 3919 } else { 3920 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3921 3922 /* We assume that cells with a valid type have faces with a valid type */ 3923 closure[off++] = p; 3924 closure[off++] = ornt; 3925 for (t = 0; t < tmpSize; ++t) { 3926 DMPolytopeType ft; 3927 3928 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3929 closure[off++] = tmp[arr[t]]; 3930 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3931 } 3932 } 3933 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3934 if (numPoints) *numPoints = tmpSize + 1; 3935 if (points) *points = closure; 3936 PetscFunctionReturn(PETSC_SUCCESS); 3937 } 3938 3939 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3940 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3941 { 3942 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3943 const PetscInt *cone, *ornt; 3944 PetscInt *pts, *closure = NULL; 3945 DMPolytopeType ft; 3946 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3947 PetscInt dim, coneSize, c, d, clSize, cl; 3948 3949 PetscFunctionBeginHot; 3950 PetscCall(DMGetDimension(dm, &dim)); 3951 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3952 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3953 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3954 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3955 maxSize = PetscMax(coneSeries, supportSeries); 3956 if (*points) { 3957 pts = *points; 3958 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3959 c = 0; 3960 pts[c++] = point; 3961 pts[c++] = o; 3962 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3963 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3964 for (cl = 0; cl < clSize * 2; cl += 2) { 3965 pts[c++] = closure[cl]; 3966 pts[c++] = closure[cl + 1]; 3967 } 3968 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3969 for (cl = 0; cl < clSize * 2; cl += 2) { 3970 pts[c++] = closure[cl]; 3971 pts[c++] = closure[cl + 1]; 3972 } 3973 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3974 for (d = 2; d < coneSize; ++d) { 3975 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3976 pts[c++] = cone[arr[d * 2 + 0]]; 3977 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3978 } 3979 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3980 if (dim >= 3) { 3981 for (d = 2; d < coneSize; ++d) { 3982 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3983 const PetscInt *fcone, *fornt; 3984 PetscInt fconeSize, fc, i; 3985 3986 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3987 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3988 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3989 for (fc = 0; fc < fconeSize; ++fc) { 3990 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3991 const PetscInt co = farr[fc * 2 + 1]; 3992 3993 for (i = 0; i < c; i += 2) 3994 if (pts[i] == cp) break; 3995 if (i == c) { 3996 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3997 pts[c++] = cp; 3998 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3999 } 4000 } 4001 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4002 } 4003 } 4004 *numPoints = c / 2; 4005 *points = pts; 4006 PetscFunctionReturn(PETSC_SUCCESS); 4007 } 4008 4009 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4010 { 4011 DMPolytopeType ct; 4012 PetscInt *closure, *fifo; 4013 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4014 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4015 PetscInt depth, maxSize; 4016 4017 PetscFunctionBeginHot; 4018 PetscCall(DMPlexGetDepth(dm, &depth)); 4019 if (depth == 1) { 4020 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4021 PetscFunctionReturn(PETSC_SUCCESS); 4022 } 4023 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4024 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; 4025 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4026 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4027 PetscFunctionReturn(PETSC_SUCCESS); 4028 } 4029 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4030 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4031 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4032 maxSize = PetscMax(coneSeries, supportSeries); 4033 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4034 if (*points) { 4035 closure = *points; 4036 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4037 closure[closureSize++] = p; 4038 closure[closureSize++] = ornt; 4039 fifo[fifoSize++] = p; 4040 fifo[fifoSize++] = ornt; 4041 fifo[fifoSize++] = ct; 4042 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4043 while (fifoSize - fifoStart) { 4044 const PetscInt q = fifo[fifoStart++]; 4045 const PetscInt o = fifo[fifoStart++]; 4046 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4047 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4048 const PetscInt *tmp, *tmpO = NULL; 4049 PetscInt tmpSize, t; 4050 4051 if (PetscDefined(USE_DEBUG)) { 4052 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4053 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); 4054 } 4055 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4056 for (t = 0; t < tmpSize; ++t) { 4057 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4058 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4059 const PetscInt cp = tmp[ip]; 4060 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4061 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4062 PetscInt c; 4063 4064 /* Check for duplicate */ 4065 for (c = 0; c < closureSize; c += 2) { 4066 if (closure[c] == cp) break; 4067 } 4068 if (c == closureSize) { 4069 closure[closureSize++] = cp; 4070 closure[closureSize++] = co; 4071 fifo[fifoSize++] = cp; 4072 fifo[fifoSize++] = co; 4073 fifo[fifoSize++] = ct; 4074 } 4075 } 4076 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4077 } 4078 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4079 if (numPoints) *numPoints = closureSize / 2; 4080 if (points) *points = closure; 4081 PetscFunctionReturn(PETSC_SUCCESS); 4082 } 4083 4084 /*@C 4085 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4086 4087 Not Collective 4088 4089 Input Parameters: 4090 + dm - The `DMPLEX` 4091 . p - The mesh point 4092 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4093 4094 Input/Output Parameter: 4095 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4096 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4097 4098 Output Parameter: 4099 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4100 4101 Level: beginner 4102 4103 Note: 4104 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4105 4106 Fortran Notes: 4107 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4108 4109 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4110 @*/ 4111 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4112 { 4113 PetscFunctionBeginHot; 4114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4115 if (numPoints) PetscAssertPointer(numPoints, 4); 4116 if (points) PetscAssertPointer(points, 5); 4117 if (PetscDefined(USE_DEBUG)) { 4118 PetscInt pStart, pEnd; 4119 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4120 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4121 } 4122 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4123 PetscFunctionReturn(PETSC_SUCCESS); 4124 } 4125 4126 /*@C 4127 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4128 4129 Not Collective 4130 4131 Input Parameters: 4132 + dm - The `DMPLEX` 4133 . p - The mesh point 4134 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4135 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4136 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4137 4138 Level: beginner 4139 4140 Note: 4141 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4142 4143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4144 @*/ 4145 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4146 { 4147 PetscFunctionBeginHot; 4148 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4149 if (numPoints) *numPoints = 0; 4150 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4151 PetscFunctionReturn(PETSC_SUCCESS); 4152 } 4153 4154 /*@ 4155 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4156 4157 Not Collective 4158 4159 Input Parameter: 4160 . dm - The `DMPLEX` 4161 4162 Output Parameters: 4163 + maxConeSize - The maximum number of in-edges 4164 - maxSupportSize - The maximum number of out-edges 4165 4166 Level: beginner 4167 4168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4169 @*/ 4170 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4171 { 4172 DM_Plex *mesh = (DM_Plex *)dm->data; 4173 4174 PetscFunctionBegin; 4175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4176 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4177 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4178 PetscFunctionReturn(PETSC_SUCCESS); 4179 } 4180 4181 PetscErrorCode DMSetUp_Plex(DM dm) 4182 { 4183 DM_Plex *mesh = (DM_Plex *)dm->data; 4184 PetscInt size, maxSupportSize; 4185 4186 PetscFunctionBegin; 4187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4188 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4189 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4190 PetscCall(PetscMalloc1(size, &mesh->cones)); 4191 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4192 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4193 if (maxSupportSize) { 4194 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4195 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4196 PetscCall(PetscMalloc1(size, &mesh->supports)); 4197 } 4198 PetscFunctionReturn(PETSC_SUCCESS); 4199 } 4200 4201 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4202 { 4203 PetscFunctionBegin; 4204 if (subdm) PetscCall(DMClone(dm, subdm)); 4205 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4206 if (subdm) (*subdm)->useNatural = dm->useNatural; 4207 if (dm->useNatural && dm->sfMigration) { 4208 PetscSF sfNatural; 4209 4210 (*subdm)->sfMigration = dm->sfMigration; 4211 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4212 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4213 (*subdm)->sfNatural = sfNatural; 4214 } 4215 PetscFunctionReturn(PETSC_SUCCESS); 4216 } 4217 4218 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4219 { 4220 PetscInt i = 0; 4221 4222 PetscFunctionBegin; 4223 PetscCall(DMClone(dms[0], superdm)); 4224 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4225 (*superdm)->useNatural = PETSC_FALSE; 4226 for (i = 0; i < len; i++) { 4227 if (dms[i]->useNatural && dms[i]->sfMigration) { 4228 PetscSF sfNatural; 4229 4230 (*superdm)->sfMigration = dms[i]->sfMigration; 4231 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4232 (*superdm)->useNatural = PETSC_TRUE; 4233 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4234 (*superdm)->sfNatural = sfNatural; 4235 break; 4236 } 4237 } 4238 PetscFunctionReturn(PETSC_SUCCESS); 4239 } 4240 4241 /*@ 4242 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4243 4244 Not Collective 4245 4246 Input Parameter: 4247 . dm - The `DMPLEX` 4248 4249 Level: beginner 4250 4251 Note: 4252 This should be called after all calls to `DMPlexSetCone()` 4253 4254 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4255 @*/ 4256 PetscErrorCode DMPlexSymmetrize(DM dm) 4257 { 4258 DM_Plex *mesh = (DM_Plex *)dm->data; 4259 PetscInt *offsets; 4260 PetscInt supportSize; 4261 PetscInt pStart, pEnd, p; 4262 4263 PetscFunctionBegin; 4264 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4265 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4266 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4267 /* Calculate support sizes */ 4268 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4269 for (p = pStart; p < pEnd; ++p) { 4270 PetscInt dof, off, c; 4271 4272 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4273 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4274 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4275 } 4276 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4277 /* Calculate supports */ 4278 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4279 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4280 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4281 for (p = pStart; p < pEnd; ++p) { 4282 PetscInt dof, off, c; 4283 4284 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4285 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4286 for (c = off; c < off + dof; ++c) { 4287 const PetscInt q = mesh->cones[c]; 4288 PetscInt offS; 4289 4290 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4291 4292 mesh->supports[offS + offsets[q]] = p; 4293 ++offsets[q]; 4294 } 4295 } 4296 PetscCall(PetscFree(offsets)); 4297 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4298 PetscFunctionReturn(PETSC_SUCCESS); 4299 } 4300 4301 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4302 { 4303 IS stratumIS; 4304 4305 PetscFunctionBegin; 4306 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4307 if (PetscDefined(USE_DEBUG)) { 4308 PetscInt qStart, qEnd, numLevels, level; 4309 PetscBool overlap = PETSC_FALSE; 4310 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4311 for (level = 0; level < numLevels; level++) { 4312 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4313 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4314 overlap = PETSC_TRUE; 4315 break; 4316 } 4317 } 4318 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); 4319 } 4320 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4321 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4322 PetscCall(ISDestroy(&stratumIS)); 4323 PetscFunctionReturn(PETSC_SUCCESS); 4324 } 4325 4326 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4327 { 4328 PetscInt *pMin, *pMax; 4329 PetscInt pStart, pEnd; 4330 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4331 4332 PetscFunctionBegin; 4333 { 4334 DMLabel label2; 4335 4336 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4337 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4338 } 4339 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4340 for (PetscInt p = pStart; p < pEnd; ++p) { 4341 DMPolytopeType ct; 4342 4343 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4344 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4345 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4346 } 4347 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4348 for (PetscInt d = dmin; d <= dmax; ++d) { 4349 pMin[d] = PETSC_MAX_INT; 4350 pMax[d] = PETSC_MIN_INT; 4351 } 4352 for (PetscInt p = pStart; p < pEnd; ++p) { 4353 DMPolytopeType ct; 4354 PetscInt d; 4355 4356 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4357 d = DMPolytopeTypeGetDim(ct); 4358 pMin[d] = PetscMin(p, pMin[d]); 4359 pMax[d] = PetscMax(p, pMax[d]); 4360 } 4361 for (PetscInt d = dmin; d <= dmax; ++d) { 4362 if (pMin[d] > pMax[d]) continue; 4363 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4364 } 4365 PetscCall(PetscFree2(pMin, pMax)); 4366 PetscFunctionReturn(PETSC_SUCCESS); 4367 } 4368 4369 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4370 { 4371 PetscInt pStart, pEnd; 4372 PetscInt numRoots = 0, numLeaves = 0; 4373 4374 PetscFunctionBegin; 4375 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4376 { 4377 /* Initialize roots and count leaves */ 4378 PetscInt sMin = PETSC_MAX_INT; 4379 PetscInt sMax = PETSC_MIN_INT; 4380 PetscInt coneSize, supportSize; 4381 4382 for (PetscInt p = pStart; p < pEnd; ++p) { 4383 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4384 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4385 if (!coneSize && supportSize) { 4386 sMin = PetscMin(p, sMin); 4387 sMax = PetscMax(p, sMax); 4388 ++numRoots; 4389 } else if (!supportSize && coneSize) { 4390 ++numLeaves; 4391 } else if (!supportSize && !coneSize) { 4392 /* Isolated points */ 4393 sMin = PetscMin(p, sMin); 4394 sMax = PetscMax(p, sMax); 4395 } 4396 } 4397 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4398 } 4399 4400 if (numRoots + numLeaves == (pEnd - pStart)) { 4401 PetscInt sMin = PETSC_MAX_INT; 4402 PetscInt sMax = PETSC_MIN_INT; 4403 PetscInt coneSize, supportSize; 4404 4405 for (PetscInt p = pStart; p < pEnd; ++p) { 4406 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4407 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4408 if (!supportSize && coneSize) { 4409 sMin = PetscMin(p, sMin); 4410 sMax = PetscMax(p, sMax); 4411 } 4412 } 4413 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4414 } else { 4415 PetscInt level = 0; 4416 PetscInt qStart, qEnd; 4417 4418 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4419 while (qEnd > qStart) { 4420 PetscInt sMin = PETSC_MAX_INT; 4421 PetscInt sMax = PETSC_MIN_INT; 4422 4423 for (PetscInt q = qStart; q < qEnd; ++q) { 4424 const PetscInt *support; 4425 PetscInt supportSize; 4426 4427 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4428 PetscCall(DMPlexGetSupport(dm, q, &support)); 4429 for (PetscInt s = 0; s < supportSize; ++s) { 4430 sMin = PetscMin(support[s], sMin); 4431 sMax = PetscMax(support[s], sMax); 4432 } 4433 } 4434 PetscCall(DMLabelGetNumValues(label, &level)); 4435 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4436 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4437 } 4438 } 4439 PetscFunctionReturn(PETSC_SUCCESS); 4440 } 4441 4442 /*@ 4443 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4444 4445 Collective 4446 4447 Input Parameter: 4448 . dm - The `DMPLEX` 4449 4450 Level: beginner 4451 4452 Notes: 4453 The strata group all points of the same grade, and this function calculates the strata. This 4454 grade can be seen as the height (or depth) of the point in the DAG. 4455 4456 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4457 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4458 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4459 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4460 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4461 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4462 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4463 4464 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4465 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4466 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 4467 to interpolate only that one (e0), so that 4468 .vb 4469 cone(c0) = {e0, v2} 4470 cone(e0) = {v0, v1} 4471 .ve 4472 If `DMPlexStratify()` is run on this mesh, it will give depths 4473 .vb 4474 depth 0 = {v0, v1, v2} 4475 depth 1 = {e0, c0} 4476 .ve 4477 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4478 4479 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4480 4481 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4482 @*/ 4483 PetscErrorCode DMPlexStratify(DM dm) 4484 { 4485 DM_Plex *mesh = (DM_Plex *)dm->data; 4486 DMLabel label; 4487 PetscBool flg = PETSC_FALSE; 4488 4489 PetscFunctionBegin; 4490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4491 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4492 4493 // Create depth label 4494 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4495 PetscCall(DMCreateLabel(dm, "depth")); 4496 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4497 4498 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4499 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4500 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4501 4502 { /* just in case there is an empty process */ 4503 PetscInt numValues, maxValues = 0, v; 4504 4505 PetscCall(DMLabelGetNumValues(label, &numValues)); 4506 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4507 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4508 } 4509 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4510 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4511 PetscFunctionReturn(PETSC_SUCCESS); 4512 } 4513 4514 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4515 { 4516 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4517 PetscInt dim, depth, pheight, coneSize; 4518 4519 PetscFunctionBeginHot; 4520 PetscCall(DMGetDimension(dm, &dim)); 4521 PetscCall(DMPlexGetDepth(dm, &depth)); 4522 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4523 pheight = depth - pdepth; 4524 if (depth <= 1) { 4525 switch (pdepth) { 4526 case 0: 4527 ct = DM_POLYTOPE_POINT; 4528 break; 4529 case 1: 4530 switch (coneSize) { 4531 case 2: 4532 ct = DM_POLYTOPE_SEGMENT; 4533 break; 4534 case 3: 4535 ct = DM_POLYTOPE_TRIANGLE; 4536 break; 4537 case 4: 4538 switch (dim) { 4539 case 2: 4540 ct = DM_POLYTOPE_QUADRILATERAL; 4541 break; 4542 case 3: 4543 ct = DM_POLYTOPE_TETRAHEDRON; 4544 break; 4545 default: 4546 break; 4547 } 4548 break; 4549 case 5: 4550 ct = DM_POLYTOPE_PYRAMID; 4551 break; 4552 case 6: 4553 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4554 break; 4555 case 8: 4556 ct = DM_POLYTOPE_HEXAHEDRON; 4557 break; 4558 default: 4559 break; 4560 } 4561 } 4562 } else { 4563 if (pdepth == 0) { 4564 ct = DM_POLYTOPE_POINT; 4565 } else if (pheight == 0) { 4566 switch (dim) { 4567 case 1: 4568 switch (coneSize) { 4569 case 2: 4570 ct = DM_POLYTOPE_SEGMENT; 4571 break; 4572 default: 4573 break; 4574 } 4575 break; 4576 case 2: 4577 switch (coneSize) { 4578 case 3: 4579 ct = DM_POLYTOPE_TRIANGLE; 4580 break; 4581 case 4: 4582 ct = DM_POLYTOPE_QUADRILATERAL; 4583 break; 4584 default: 4585 break; 4586 } 4587 break; 4588 case 3: 4589 switch (coneSize) { 4590 case 4: 4591 ct = DM_POLYTOPE_TETRAHEDRON; 4592 break; 4593 case 5: { 4594 const PetscInt *cone; 4595 PetscInt faceConeSize; 4596 4597 PetscCall(DMPlexGetCone(dm, p, &cone)); 4598 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4599 switch (faceConeSize) { 4600 case 3: 4601 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4602 break; 4603 case 4: 4604 ct = DM_POLYTOPE_PYRAMID; 4605 break; 4606 } 4607 } break; 4608 case 6: 4609 ct = DM_POLYTOPE_HEXAHEDRON; 4610 break; 4611 default: 4612 break; 4613 } 4614 break; 4615 default: 4616 break; 4617 } 4618 } else if (pheight > 0) { 4619 switch (coneSize) { 4620 case 2: 4621 ct = DM_POLYTOPE_SEGMENT; 4622 break; 4623 case 3: 4624 ct = DM_POLYTOPE_TRIANGLE; 4625 break; 4626 case 4: 4627 ct = DM_POLYTOPE_QUADRILATERAL; 4628 break; 4629 default: 4630 break; 4631 } 4632 } 4633 } 4634 *pt = ct; 4635 PetscFunctionReturn(PETSC_SUCCESS); 4636 } 4637 4638 /*@ 4639 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4640 4641 Collective 4642 4643 Input Parameter: 4644 . dm - The `DMPLEX` 4645 4646 Level: developer 4647 4648 Note: 4649 This function is normally called automatically when a cell type is requested. It creates an 4650 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4651 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4652 4653 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4654 4655 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4656 @*/ 4657 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4658 { 4659 DM_Plex *mesh; 4660 DMLabel ctLabel; 4661 PetscInt pStart, pEnd, p; 4662 4663 PetscFunctionBegin; 4664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4665 mesh = (DM_Plex *)dm->data; 4666 PetscCall(DMCreateLabel(dm, "celltype")); 4667 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4668 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4669 PetscCall(PetscFree(mesh->cellTypes)); 4670 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4671 for (p = pStart; p < pEnd; ++p) { 4672 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4673 PetscInt pdepth; 4674 4675 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4676 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4677 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4678 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4679 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4680 } 4681 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4682 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4683 PetscFunctionReturn(PETSC_SUCCESS); 4684 } 4685 4686 /*@C 4687 DMPlexGetJoin - Get an array for the join of the set of points 4688 4689 Not Collective 4690 4691 Input Parameters: 4692 + dm - The `DMPLEX` object 4693 . numPoints - The number of input points for the join 4694 - points - The input points 4695 4696 Output Parameters: 4697 + numCoveredPoints - The number of points in the join 4698 - coveredPoints - The points in the join 4699 4700 Level: intermediate 4701 4702 Note: 4703 Currently, this is restricted to a single level join 4704 4705 Fortran Notes: 4706 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4707 4708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4709 @*/ 4710 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4711 { 4712 DM_Plex *mesh = (DM_Plex *)dm->data; 4713 PetscInt *join[2]; 4714 PetscInt joinSize, i = 0; 4715 PetscInt dof, off, p, c, m; 4716 PetscInt maxSupportSize; 4717 4718 PetscFunctionBegin; 4719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4720 PetscAssertPointer(points, 3); 4721 PetscAssertPointer(numCoveredPoints, 4); 4722 PetscAssertPointer(coveredPoints, 5); 4723 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4724 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4725 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4726 /* Copy in support of first point */ 4727 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4728 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4729 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4730 /* Check each successive support */ 4731 for (p = 1; p < numPoints; ++p) { 4732 PetscInt newJoinSize = 0; 4733 4734 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4735 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4736 for (c = 0; c < dof; ++c) { 4737 const PetscInt point = mesh->supports[off + c]; 4738 4739 for (m = 0; m < joinSize; ++m) { 4740 if (point == join[i][m]) { 4741 join[1 - i][newJoinSize++] = point; 4742 break; 4743 } 4744 } 4745 } 4746 joinSize = newJoinSize; 4747 i = 1 - i; 4748 } 4749 *numCoveredPoints = joinSize; 4750 *coveredPoints = join[i]; 4751 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4752 PetscFunctionReturn(PETSC_SUCCESS); 4753 } 4754 4755 /*@C 4756 DMPlexRestoreJoin - Restore an array for the join of the set of points 4757 4758 Not Collective 4759 4760 Input Parameters: 4761 + dm - The `DMPLEX` object 4762 . numPoints - The number of input points for the join 4763 - points - The input points 4764 4765 Output Parameters: 4766 + numCoveredPoints - The number of points in the join 4767 - coveredPoints - The points in the join 4768 4769 Level: intermediate 4770 4771 Fortran Notes: 4772 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4773 4774 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4775 @*/ 4776 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4777 { 4778 PetscFunctionBegin; 4779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4780 if (points) PetscAssertPointer(points, 3); 4781 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4782 PetscAssertPointer(coveredPoints, 5); 4783 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4784 if (numCoveredPoints) *numCoveredPoints = 0; 4785 PetscFunctionReturn(PETSC_SUCCESS); 4786 } 4787 4788 /*@C 4789 DMPlexGetFullJoin - Get an array for the join of the set of points 4790 4791 Not Collective 4792 4793 Input Parameters: 4794 + dm - The `DMPLEX` object 4795 . numPoints - The number of input points for the join 4796 - points - The input points 4797 4798 Output Parameters: 4799 + numCoveredPoints - The number of points in the join 4800 - coveredPoints - The points in the join 4801 4802 Level: intermediate 4803 4804 Fortran Notes: 4805 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4806 4807 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4808 @*/ 4809 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4810 { 4811 PetscInt *offsets, **closures; 4812 PetscInt *join[2]; 4813 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4814 PetscInt p, d, c, m, ms; 4815 4816 PetscFunctionBegin; 4817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4818 PetscAssertPointer(points, 3); 4819 PetscAssertPointer(numCoveredPoints, 4); 4820 PetscAssertPointer(coveredPoints, 5); 4821 4822 PetscCall(DMPlexGetDepth(dm, &depth)); 4823 PetscCall(PetscCalloc1(numPoints, &closures)); 4824 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4825 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4826 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4827 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4828 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4829 4830 for (p = 0; p < numPoints; ++p) { 4831 PetscInt closureSize; 4832 4833 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4834 4835 offsets[p * (depth + 2) + 0] = 0; 4836 for (d = 0; d < depth + 1; ++d) { 4837 PetscInt pStart, pEnd, i; 4838 4839 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4840 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4841 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4842 offsets[p * (depth + 2) + d + 1] = i; 4843 break; 4844 } 4845 } 4846 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4847 } 4848 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); 4849 } 4850 for (d = 0; d < depth + 1; ++d) { 4851 PetscInt dof; 4852 4853 /* Copy in support of first point */ 4854 dof = offsets[d + 1] - offsets[d]; 4855 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4856 /* Check each successive cone */ 4857 for (p = 1; p < numPoints && joinSize; ++p) { 4858 PetscInt newJoinSize = 0; 4859 4860 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4861 for (c = 0; c < dof; ++c) { 4862 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4863 4864 for (m = 0; m < joinSize; ++m) { 4865 if (point == join[i][m]) { 4866 join[1 - i][newJoinSize++] = point; 4867 break; 4868 } 4869 } 4870 } 4871 joinSize = newJoinSize; 4872 i = 1 - i; 4873 } 4874 if (joinSize) break; 4875 } 4876 *numCoveredPoints = joinSize; 4877 *coveredPoints = join[i]; 4878 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4879 PetscCall(PetscFree(closures)); 4880 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4881 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4882 PetscFunctionReturn(PETSC_SUCCESS); 4883 } 4884 4885 /*@C 4886 DMPlexGetMeet - Get an array for the meet of the set of points 4887 4888 Not Collective 4889 4890 Input Parameters: 4891 + dm - The `DMPLEX` object 4892 . numPoints - The number of input points for the meet 4893 - points - The input points 4894 4895 Output Parameters: 4896 + numCoveringPoints - The number of points in the meet 4897 - coveringPoints - The points in the meet 4898 4899 Level: intermediate 4900 4901 Note: 4902 Currently, this is restricted to a single level meet 4903 4904 Fortran Notes: 4905 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4906 4907 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4908 @*/ 4909 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4910 { 4911 DM_Plex *mesh = (DM_Plex *)dm->data; 4912 PetscInt *meet[2]; 4913 PetscInt meetSize, i = 0; 4914 PetscInt dof, off, p, c, m; 4915 PetscInt maxConeSize; 4916 4917 PetscFunctionBegin; 4918 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4919 PetscAssertPointer(points, 3); 4920 PetscAssertPointer(numCoveringPoints, 4); 4921 PetscAssertPointer(coveringPoints, 5); 4922 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4923 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4924 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4925 /* Copy in cone of first point */ 4926 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4927 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4928 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4929 /* Check each successive cone */ 4930 for (p = 1; p < numPoints; ++p) { 4931 PetscInt newMeetSize = 0; 4932 4933 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4934 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4935 for (c = 0; c < dof; ++c) { 4936 const PetscInt point = mesh->cones[off + c]; 4937 4938 for (m = 0; m < meetSize; ++m) { 4939 if (point == meet[i][m]) { 4940 meet[1 - i][newMeetSize++] = point; 4941 break; 4942 } 4943 } 4944 } 4945 meetSize = newMeetSize; 4946 i = 1 - i; 4947 } 4948 *numCoveringPoints = meetSize; 4949 *coveringPoints = meet[i]; 4950 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4951 PetscFunctionReturn(PETSC_SUCCESS); 4952 } 4953 4954 /*@C 4955 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4956 4957 Not Collective 4958 4959 Input Parameters: 4960 + dm - The `DMPLEX` object 4961 . numPoints - The number of input points for the meet 4962 - points - The input points 4963 4964 Output Parameters: 4965 + numCoveredPoints - The number of points in the meet 4966 - coveredPoints - The points in the meet 4967 4968 Level: intermediate 4969 4970 Fortran Notes: 4971 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4972 4973 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4974 @*/ 4975 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4976 { 4977 PetscFunctionBegin; 4978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4979 if (points) PetscAssertPointer(points, 3); 4980 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4981 PetscAssertPointer(coveredPoints, 5); 4982 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4983 if (numCoveredPoints) *numCoveredPoints = 0; 4984 PetscFunctionReturn(PETSC_SUCCESS); 4985 } 4986 4987 /*@C 4988 DMPlexGetFullMeet - Get an array for the meet of the set of points 4989 4990 Not Collective 4991 4992 Input Parameters: 4993 + dm - The `DMPLEX` object 4994 . numPoints - The number of input points for the meet 4995 - points - The input points 4996 4997 Output Parameters: 4998 + numCoveredPoints - The number of points in the meet 4999 - coveredPoints - The points in the meet 5000 5001 Level: intermediate 5002 5003 Fortran Notes: 5004 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5005 5006 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5007 @*/ 5008 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 5009 { 5010 PetscInt *offsets, **closures; 5011 PetscInt *meet[2]; 5012 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5013 PetscInt p, h, c, m, mc; 5014 5015 PetscFunctionBegin; 5016 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5017 PetscAssertPointer(points, 3); 5018 PetscAssertPointer(numCoveredPoints, 4); 5019 PetscAssertPointer(coveredPoints, 5); 5020 5021 PetscCall(DMPlexGetDepth(dm, &height)); 5022 PetscCall(PetscMalloc1(numPoints, &closures)); 5023 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5024 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5025 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5026 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5027 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5028 5029 for (p = 0; p < numPoints; ++p) { 5030 PetscInt closureSize; 5031 5032 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5033 5034 offsets[p * (height + 2) + 0] = 0; 5035 for (h = 0; h < height + 1; ++h) { 5036 PetscInt pStart, pEnd, i; 5037 5038 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5039 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5040 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5041 offsets[p * (height + 2) + h + 1] = i; 5042 break; 5043 } 5044 } 5045 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5046 } 5047 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); 5048 } 5049 for (h = 0; h < height + 1; ++h) { 5050 PetscInt dof; 5051 5052 /* Copy in cone of first point */ 5053 dof = offsets[h + 1] - offsets[h]; 5054 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5055 /* Check each successive cone */ 5056 for (p = 1; p < numPoints && meetSize; ++p) { 5057 PetscInt newMeetSize = 0; 5058 5059 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5060 for (c = 0; c < dof; ++c) { 5061 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5062 5063 for (m = 0; m < meetSize; ++m) { 5064 if (point == meet[i][m]) { 5065 meet[1 - i][newMeetSize++] = point; 5066 break; 5067 } 5068 } 5069 } 5070 meetSize = newMeetSize; 5071 i = 1 - i; 5072 } 5073 if (meetSize) break; 5074 } 5075 *numCoveredPoints = meetSize; 5076 *coveredPoints = meet[i]; 5077 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5078 PetscCall(PetscFree(closures)); 5079 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5080 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5081 PetscFunctionReturn(PETSC_SUCCESS); 5082 } 5083 5084 /*@ 5085 DMPlexEqual - Determine if two `DM` have the same topology 5086 5087 Not Collective 5088 5089 Input Parameters: 5090 + dmA - A `DMPLEX` object 5091 - dmB - A `DMPLEX` object 5092 5093 Output Parameter: 5094 . equal - `PETSC_TRUE` if the topologies are identical 5095 5096 Level: intermediate 5097 5098 Note: 5099 We are not solving graph isomorphism, so we do not permute. 5100 5101 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5102 @*/ 5103 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5104 { 5105 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5106 5107 PetscFunctionBegin; 5108 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5109 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5110 PetscAssertPointer(equal, 3); 5111 5112 *equal = PETSC_FALSE; 5113 PetscCall(DMPlexGetDepth(dmA, &depth)); 5114 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5115 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5116 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5117 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5118 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5119 for (p = pStart; p < pEnd; ++p) { 5120 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5121 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5122 5123 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5124 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5125 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5126 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5127 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5128 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5129 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5130 for (c = 0; c < coneSize; ++c) { 5131 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5132 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5133 } 5134 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5135 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5136 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5137 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5138 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5139 for (s = 0; s < supportSize; ++s) { 5140 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5141 } 5142 } 5143 *equal = PETSC_TRUE; 5144 PetscFunctionReturn(PETSC_SUCCESS); 5145 } 5146 5147 /*@ 5148 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5149 5150 Not Collective 5151 5152 Input Parameters: 5153 + dm - The `DMPLEX` 5154 . cellDim - The cell dimension 5155 - numCorners - The number of vertices on a cell 5156 5157 Output Parameter: 5158 . numFaceVertices - The number of vertices on a face 5159 5160 Level: developer 5161 5162 Note: 5163 Of course this can only work for a restricted set of symmetric shapes 5164 5165 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5166 @*/ 5167 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5168 { 5169 MPI_Comm comm; 5170 5171 PetscFunctionBegin; 5172 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5173 PetscAssertPointer(numFaceVertices, 4); 5174 switch (cellDim) { 5175 case 0: 5176 *numFaceVertices = 0; 5177 break; 5178 case 1: 5179 *numFaceVertices = 1; 5180 break; 5181 case 2: 5182 switch (numCorners) { 5183 case 3: /* triangle */ 5184 *numFaceVertices = 2; /* Edge has 2 vertices */ 5185 break; 5186 case 4: /* quadrilateral */ 5187 *numFaceVertices = 2; /* Edge has 2 vertices */ 5188 break; 5189 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5190 *numFaceVertices = 3; /* Edge has 3 vertices */ 5191 break; 5192 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5193 *numFaceVertices = 3; /* Edge has 3 vertices */ 5194 break; 5195 default: 5196 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5197 } 5198 break; 5199 case 3: 5200 switch (numCorners) { 5201 case 4: /* tetradehdron */ 5202 *numFaceVertices = 3; /* Face has 3 vertices */ 5203 break; 5204 case 6: /* tet cohesive cells */ 5205 *numFaceVertices = 4; /* Face has 4 vertices */ 5206 break; 5207 case 8: /* hexahedron */ 5208 *numFaceVertices = 4; /* Face has 4 vertices */ 5209 break; 5210 case 9: /* tet cohesive Lagrange cells */ 5211 *numFaceVertices = 6; /* Face has 6 vertices */ 5212 break; 5213 case 10: /* quadratic tetrahedron */ 5214 *numFaceVertices = 6; /* Face has 6 vertices */ 5215 break; 5216 case 12: /* hex cohesive Lagrange cells */ 5217 *numFaceVertices = 6; /* Face has 6 vertices */ 5218 break; 5219 case 18: /* quadratic tet cohesive Lagrange cells */ 5220 *numFaceVertices = 6; /* Face has 6 vertices */ 5221 break; 5222 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5223 *numFaceVertices = 9; /* Face has 9 vertices */ 5224 break; 5225 default: 5226 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5227 } 5228 break; 5229 default: 5230 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5231 } 5232 PetscFunctionReturn(PETSC_SUCCESS); 5233 } 5234 5235 /*@ 5236 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5237 5238 Not Collective 5239 5240 Input Parameter: 5241 . dm - The `DMPLEX` object 5242 5243 Output Parameter: 5244 . depthLabel - The `DMLabel` recording point depth 5245 5246 Level: developer 5247 5248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5249 @*/ 5250 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5251 { 5252 PetscFunctionBegin; 5253 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5254 PetscAssertPointer(depthLabel, 2); 5255 *depthLabel = dm->depthLabel; 5256 PetscFunctionReturn(PETSC_SUCCESS); 5257 } 5258 5259 /*@ 5260 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5261 5262 Not Collective 5263 5264 Input Parameter: 5265 . dm - The `DMPLEX` object 5266 5267 Output Parameter: 5268 . depth - The number of strata (breadth first levels) in the DAG 5269 5270 Level: developer 5271 5272 Notes: 5273 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5274 5275 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5276 5277 An empty mesh gives -1. 5278 5279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5280 @*/ 5281 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5282 { 5283 DM_Plex *mesh = (DM_Plex *)dm->data; 5284 DMLabel label; 5285 PetscInt d = -1; 5286 5287 PetscFunctionBegin; 5288 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5289 PetscAssertPointer(depth, 2); 5290 if (mesh->tr) { 5291 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5292 } else { 5293 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5294 // Allow missing depths 5295 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5296 *depth = d; 5297 } 5298 PetscFunctionReturn(PETSC_SUCCESS); 5299 } 5300 5301 /*@ 5302 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5303 5304 Not Collective 5305 5306 Input Parameters: 5307 + dm - The `DMPLEX` object 5308 - depth - The requested depth 5309 5310 Output Parameters: 5311 + start - The first point at this `depth` 5312 - end - One beyond the last point at this `depth` 5313 5314 Level: developer 5315 5316 Notes: 5317 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5318 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5319 higher dimension, e.g., "edges". 5320 5321 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5322 @*/ 5323 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5324 { 5325 DM_Plex *mesh = (DM_Plex *)dm->data; 5326 DMLabel label; 5327 PetscInt pStart, pEnd; 5328 5329 PetscFunctionBegin; 5330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5331 if (start) { 5332 PetscAssertPointer(start, 3); 5333 *start = 0; 5334 } 5335 if (end) { 5336 PetscAssertPointer(end, 4); 5337 *end = 0; 5338 } 5339 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5340 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5341 if (depth < 0) { 5342 if (start) *start = pStart; 5343 if (end) *end = pEnd; 5344 PetscFunctionReturn(PETSC_SUCCESS); 5345 } 5346 if (mesh->tr) { 5347 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5348 } else { 5349 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5350 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5351 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5352 } 5353 PetscFunctionReturn(PETSC_SUCCESS); 5354 } 5355 5356 /*@ 5357 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5358 5359 Not Collective 5360 5361 Input Parameters: 5362 + dm - The `DMPLEX` object 5363 - height - The requested height 5364 5365 Output Parameters: 5366 + start - The first point at this `height` 5367 - end - One beyond the last point at this `height` 5368 5369 Level: developer 5370 5371 Notes: 5372 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5373 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5374 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5375 5376 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5377 @*/ 5378 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5379 { 5380 DMLabel label; 5381 PetscInt depth, pStart, pEnd; 5382 5383 PetscFunctionBegin; 5384 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5385 if (start) { 5386 PetscAssertPointer(start, 3); 5387 *start = 0; 5388 } 5389 if (end) { 5390 PetscAssertPointer(end, 4); 5391 *end = 0; 5392 } 5393 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5394 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5395 if (height < 0) { 5396 if (start) *start = pStart; 5397 if (end) *end = pEnd; 5398 PetscFunctionReturn(PETSC_SUCCESS); 5399 } 5400 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5401 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5402 else PetscCall(DMGetDimension(dm, &depth)); 5403 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5404 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5405 PetscFunctionReturn(PETSC_SUCCESS); 5406 } 5407 5408 /*@ 5409 DMPlexGetPointDepth - Get the `depth` of a given point 5410 5411 Not Collective 5412 5413 Input Parameters: 5414 + dm - The `DMPLEX` object 5415 - point - The point 5416 5417 Output Parameter: 5418 . depth - The depth of the `point` 5419 5420 Level: intermediate 5421 5422 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5423 @*/ 5424 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5425 { 5426 PetscFunctionBegin; 5427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5428 PetscAssertPointer(depth, 3); 5429 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5430 PetscFunctionReturn(PETSC_SUCCESS); 5431 } 5432 5433 /*@ 5434 DMPlexGetPointHeight - Get the `height` of a given point 5435 5436 Not Collective 5437 5438 Input Parameters: 5439 + dm - The `DMPLEX` object 5440 - point - The point 5441 5442 Output Parameter: 5443 . height - The height of the `point` 5444 5445 Level: intermediate 5446 5447 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5448 @*/ 5449 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5450 { 5451 PetscInt n, pDepth; 5452 5453 PetscFunctionBegin; 5454 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5455 PetscAssertPointer(height, 3); 5456 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5457 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5458 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5459 PetscFunctionReturn(PETSC_SUCCESS); 5460 } 5461 5462 /*@ 5463 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5464 5465 Not Collective 5466 5467 Input Parameter: 5468 . dm - The `DMPLEX` object 5469 5470 Output Parameter: 5471 . celltypeLabel - The `DMLabel` recording cell polytope type 5472 5473 Level: developer 5474 5475 Note: 5476 This function will trigger automatica computation of cell types. This can be disabled by calling 5477 `DMCreateLabel`(dm, "celltype") beforehand. 5478 5479 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5480 @*/ 5481 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5482 { 5483 PetscFunctionBegin; 5484 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5485 PetscAssertPointer(celltypeLabel, 2); 5486 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5487 *celltypeLabel = dm->celltypeLabel; 5488 PetscFunctionReturn(PETSC_SUCCESS); 5489 } 5490 5491 /*@ 5492 DMPlexGetCellType - Get the polytope type of a given cell 5493 5494 Not Collective 5495 5496 Input Parameters: 5497 + dm - The `DMPLEX` object 5498 - cell - The cell 5499 5500 Output Parameter: 5501 . celltype - The polytope type of the cell 5502 5503 Level: intermediate 5504 5505 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5506 @*/ 5507 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5508 { 5509 DM_Plex *mesh = (DM_Plex *)dm->data; 5510 DMLabel label; 5511 PetscInt ct; 5512 5513 PetscFunctionBegin; 5514 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5515 PetscAssertPointer(celltype, 3); 5516 if (mesh->tr) { 5517 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5518 } else { 5519 PetscInt pStart, pEnd; 5520 5521 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5522 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5523 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5524 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5525 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5526 for (PetscInt p = pStart; p < pEnd; p++) { 5527 PetscCall(DMLabelGetValue(label, p, &ct)); 5528 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5529 } 5530 } 5531 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5532 if (PetscDefined(USE_DEBUG)) { 5533 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5534 PetscCall(DMLabelGetValue(label, cell, &ct)); 5535 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5536 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5537 } 5538 } 5539 PetscFunctionReturn(PETSC_SUCCESS); 5540 } 5541 5542 /*@ 5543 DMPlexSetCellType - Set the polytope type of a given cell 5544 5545 Not Collective 5546 5547 Input Parameters: 5548 + dm - The `DMPLEX` object 5549 . cell - The cell 5550 - celltype - The polytope type of the cell 5551 5552 Level: advanced 5553 5554 Note: 5555 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5556 is executed. This function will override the computed type. However, if automatic classification will not succeed 5557 and a user wants to manually specify all types, the classification must be disabled by calling 5558 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5559 5560 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5561 @*/ 5562 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5563 { 5564 DM_Plex *mesh = (DM_Plex *)dm->data; 5565 DMLabel label; 5566 PetscInt pStart, pEnd; 5567 5568 PetscFunctionBegin; 5569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5570 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5571 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5572 PetscCall(DMLabelSetValue(label, cell, celltype)); 5573 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5574 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5575 PetscFunctionReturn(PETSC_SUCCESS); 5576 } 5577 5578 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5579 { 5580 PetscSection section; 5581 PetscInt maxHeight; 5582 const char *prefix; 5583 5584 PetscFunctionBegin; 5585 PetscCall(DMClone(dm, cdm)); 5586 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5587 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5588 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5589 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5590 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5591 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5592 PetscCall(DMSetLocalSection(*cdm, section)); 5593 PetscCall(PetscSectionDestroy(§ion)); 5594 5595 PetscCall(DMSetNumFields(*cdm, 1)); 5596 PetscCall(DMCreateDS(*cdm)); 5597 (*cdm)->cloneOpts = PETSC_TRUE; 5598 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5599 PetscFunctionReturn(PETSC_SUCCESS); 5600 } 5601 5602 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5603 { 5604 Vec coordsLocal, cellCoordsLocal; 5605 DM coordsDM, cellCoordsDM; 5606 5607 PetscFunctionBegin; 5608 *field = NULL; 5609 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5610 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5611 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5612 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5613 if (coordsLocal && coordsDM) { 5614 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5615 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5616 } 5617 PetscFunctionReturn(PETSC_SUCCESS); 5618 } 5619 5620 /*@ 5621 DMPlexGetConeSection - Return a section which describes the layout of cone data 5622 5623 Not Collective 5624 5625 Input Parameter: 5626 . dm - The `DMPLEX` object 5627 5628 Output Parameter: 5629 . section - The `PetscSection` object 5630 5631 Level: developer 5632 5633 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5634 @*/ 5635 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5636 { 5637 DM_Plex *mesh = (DM_Plex *)dm->data; 5638 5639 PetscFunctionBegin; 5640 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5641 if (section) *section = mesh->coneSection; 5642 PetscFunctionReturn(PETSC_SUCCESS); 5643 } 5644 5645 /*@ 5646 DMPlexGetSupportSection - Return a section which describes the layout of support data 5647 5648 Not Collective 5649 5650 Input Parameter: 5651 . dm - The `DMPLEX` object 5652 5653 Output Parameter: 5654 . section - The `PetscSection` object 5655 5656 Level: developer 5657 5658 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5659 @*/ 5660 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5661 { 5662 DM_Plex *mesh = (DM_Plex *)dm->data; 5663 5664 PetscFunctionBegin; 5665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5666 if (section) *section = mesh->supportSection; 5667 PetscFunctionReturn(PETSC_SUCCESS); 5668 } 5669 5670 /*@C 5671 DMPlexGetCones - Return cone data 5672 5673 Not Collective 5674 5675 Input Parameter: 5676 . dm - The `DMPLEX` object 5677 5678 Output Parameter: 5679 . cones - The cone for each point 5680 5681 Level: developer 5682 5683 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5684 @*/ 5685 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5686 { 5687 DM_Plex *mesh = (DM_Plex *)dm->data; 5688 5689 PetscFunctionBegin; 5690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5691 if (cones) *cones = mesh->cones; 5692 PetscFunctionReturn(PETSC_SUCCESS); 5693 } 5694 5695 /*@C 5696 DMPlexGetConeOrientations - Return cone orientation data 5697 5698 Not Collective 5699 5700 Input Parameter: 5701 . dm - The `DMPLEX` object 5702 5703 Output Parameter: 5704 . coneOrientations - The array of cone orientations for all points 5705 5706 Level: developer 5707 5708 Notes: 5709 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5710 5711 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5712 5713 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5714 @*/ 5715 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5716 { 5717 DM_Plex *mesh = (DM_Plex *)dm->data; 5718 5719 PetscFunctionBegin; 5720 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5721 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5722 PetscFunctionReturn(PETSC_SUCCESS); 5723 } 5724 5725 /******************************** FEM Support **********************************/ 5726 5727 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5728 { 5729 PetscInt depth; 5730 5731 PetscFunctionBegin; 5732 PetscCall(DMPlexGetDepth(plex, &depth)); 5733 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5734 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5735 PetscFunctionReturn(PETSC_SUCCESS); 5736 } 5737 5738 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5739 { 5740 PetscInt depth; 5741 5742 PetscFunctionBegin; 5743 PetscCall(DMPlexGetDepth(plex, &depth)); 5744 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5745 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5746 PetscFunctionReturn(PETSC_SUCCESS); 5747 } 5748 5749 /* 5750 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5751 representing a line in the section. 5752 */ 5753 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5754 { 5755 PetscObject obj; 5756 PetscClassId id; 5757 PetscFE fe = NULL; 5758 5759 PetscFunctionBeginHot; 5760 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5761 PetscCall(DMGetField(dm, field, NULL, &obj)); 5762 PetscCall(PetscObjectGetClassId(obj, &id)); 5763 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5764 5765 if (!fe) { 5766 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5767 /* An order k SEM disc has k-1 dofs on an edge */ 5768 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5769 *k = *k / *Nc + 1; 5770 } else { 5771 PetscInt dual_space_size, dim; 5772 PetscDualSpace dsp; 5773 5774 PetscCall(DMGetDimension(dm, &dim)); 5775 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5776 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5777 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5778 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5779 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5780 } 5781 PetscFunctionReturn(PETSC_SUCCESS); 5782 } 5783 5784 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5785 { 5786 PetscFunctionBeginHot; 5787 if (tensor) { 5788 *dof = PetscPowInt(k + 1, dim); 5789 } else { 5790 switch (dim) { 5791 case 1: 5792 *dof = k + 1; 5793 break; 5794 case 2: 5795 *dof = ((k + 1) * (k + 2)) / 2; 5796 break; 5797 case 3: 5798 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5799 break; 5800 default: 5801 *dof = 0; 5802 } 5803 } 5804 PetscFunctionReturn(PETSC_SUCCESS); 5805 } 5806 5807 /*@ 5808 5809 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5810 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5811 section provided (or the section of the `DM`). 5812 5813 Input Parameters: 5814 + dm - The `DM` 5815 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5816 - section - The `PetscSection` to reorder, or `NULL` for the default section 5817 5818 Example: 5819 A typical interpolated single-quad mesh might order points as 5820 .vb 5821 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5822 5823 v4 -- e6 -- v3 5824 | | 5825 e7 c0 e8 5826 | | 5827 v1 -- e5 -- v2 5828 .ve 5829 5830 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5831 dofs in the order of points, e.g., 5832 .vb 5833 c0 -> [0,1,2,3] 5834 v1 -> [4] 5835 ... 5836 e5 -> [8, 9] 5837 .ve 5838 5839 which corresponds to the dofs 5840 .vb 5841 6 10 11 7 5842 13 2 3 15 5843 12 0 1 14 5844 4 8 9 5 5845 .ve 5846 5847 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5848 .vb 5849 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5850 .ve 5851 5852 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5853 .vb 5854 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5855 .ve 5856 5857 Level: developer 5858 5859 Notes: 5860 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5861 degree of the basis. 5862 5863 This is required to run with libCEED. 5864 5865 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5866 @*/ 5867 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5868 { 5869 DMLabel label; 5870 PetscInt dim, depth = -1, eStart = -1, Nf; 5871 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5872 5873 PetscFunctionBegin; 5874 PetscCall(DMGetDimension(dm, &dim)); 5875 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5876 if (point < 0) { 5877 PetscInt sStart, sEnd; 5878 5879 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5880 point = sEnd - sStart ? sStart : point; 5881 } 5882 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5883 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5884 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5885 if (depth == 1) { 5886 eStart = point; 5887 } else if (depth == dim) { 5888 const PetscInt *cone; 5889 5890 PetscCall(DMPlexGetCone(dm, point, &cone)); 5891 if (dim == 2) eStart = cone[0]; 5892 else if (dim == 3) { 5893 const PetscInt *cone2; 5894 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5895 eStart = cone2[0]; 5896 } 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); 5897 } 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); 5898 5899 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5900 for (PetscInt d = 1; d <= dim; d++) { 5901 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5902 PetscInt *perm; 5903 5904 for (f = 0; f < Nf; ++f) { 5905 PetscInt dof; 5906 5907 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5908 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5909 if (!continuous && d < dim) continue; 5910 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5911 size += dof * Nc; 5912 } 5913 PetscCall(PetscMalloc1(size, &perm)); 5914 for (f = 0; f < Nf; ++f) { 5915 switch (d) { 5916 case 1: 5917 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5918 if (!continuous && d < dim) continue; 5919 /* 5920 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5921 We want [ vtx0; edge of length k-1; vtx1 ] 5922 */ 5923 if (continuous) { 5924 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5925 for (i = 0; i < k - 1; i++) 5926 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5927 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5928 foffset = offset; 5929 } else { 5930 PetscInt dof; 5931 5932 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5933 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5934 foffset = offset; 5935 } 5936 break; 5937 case 2: 5938 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5939 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5940 if (!continuous && d < dim) continue; 5941 /* The SEM order is 5942 5943 v_lb, {e_b}, v_rb, 5944 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5945 v_lt, reverse {e_t}, v_rt 5946 */ 5947 if (continuous) { 5948 const PetscInt of = 0; 5949 const PetscInt oeb = of + PetscSqr(k - 1); 5950 const PetscInt oer = oeb + (k - 1); 5951 const PetscInt oet = oer + (k - 1); 5952 const PetscInt oel = oet + (k - 1); 5953 const PetscInt ovlb = oel + (k - 1); 5954 const PetscInt ovrb = ovlb + 1; 5955 const PetscInt ovrt = ovrb + 1; 5956 const PetscInt ovlt = ovrt + 1; 5957 PetscInt o; 5958 5959 /* bottom */ 5960 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5961 for (o = oeb; o < oer; ++o) 5962 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5963 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5964 /* middle */ 5965 for (i = 0; i < k - 1; ++i) { 5966 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5967 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5968 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5969 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5970 } 5971 /* top */ 5972 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5973 for (o = oel - 1; o >= oet; --o) 5974 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5975 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5976 foffset = offset; 5977 } else { 5978 PetscInt dof; 5979 5980 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5981 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5982 foffset = offset; 5983 } 5984 break; 5985 case 3: 5986 /* The original hex closure is 5987 5988 {c, 5989 f_b, f_t, f_f, f_b, f_r, f_l, 5990 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5991 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5992 */ 5993 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5994 if (!continuous && d < dim) continue; 5995 /* The SEM order is 5996 Bottom Slice 5997 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5998 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5999 v_blb, {e_bb}, v_brb, 6000 6001 Middle Slice (j) 6002 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6003 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6004 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6005 6006 Top Slice 6007 v_tlf, {e_tf}, v_trf, 6008 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6009 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6010 */ 6011 if (continuous) { 6012 const PetscInt oc = 0; 6013 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6014 const PetscInt oft = ofb + PetscSqr(k - 1); 6015 const PetscInt off = oft + PetscSqr(k - 1); 6016 const PetscInt ofk = off + PetscSqr(k - 1); 6017 const PetscInt ofr = ofk + PetscSqr(k - 1); 6018 const PetscInt ofl = ofr + PetscSqr(k - 1); 6019 const PetscInt oebl = ofl + PetscSqr(k - 1); 6020 const PetscInt oebb = oebl + (k - 1); 6021 const PetscInt oebr = oebb + (k - 1); 6022 const PetscInt oebf = oebr + (k - 1); 6023 const PetscInt oetf = oebf + (k - 1); 6024 const PetscInt oetr = oetf + (k - 1); 6025 const PetscInt oetb = oetr + (k - 1); 6026 const PetscInt oetl = oetb + (k - 1); 6027 const PetscInt oerf = oetl + (k - 1); 6028 const PetscInt oelf = oerf + (k - 1); 6029 const PetscInt oelb = oelf + (k - 1); 6030 const PetscInt oerb = oelb + (k - 1); 6031 const PetscInt ovblf = oerb + (k - 1); 6032 const PetscInt ovblb = ovblf + 1; 6033 const PetscInt ovbrb = ovblb + 1; 6034 const PetscInt ovbrf = ovbrb + 1; 6035 const PetscInt ovtlf = ovbrf + 1; 6036 const PetscInt ovtrf = ovtlf + 1; 6037 const PetscInt ovtrb = ovtrf + 1; 6038 const PetscInt ovtlb = ovtrb + 1; 6039 PetscInt o, n; 6040 6041 /* Bottom Slice */ 6042 /* bottom */ 6043 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6044 for (o = oetf - 1; o >= oebf; --o) 6045 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6046 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6047 /* middle */ 6048 for (i = 0; i < k - 1; ++i) { 6049 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6050 for (n = 0; n < k - 1; ++n) { 6051 o = ofb + n * (k - 1) + i; 6052 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6053 } 6054 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6055 } 6056 /* top */ 6057 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6058 for (o = oebb; o < oebr; ++o) 6059 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6060 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6061 6062 /* Middle Slice */ 6063 for (j = 0; j < k - 1; ++j) { 6064 /* bottom */ 6065 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6066 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6067 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6068 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6069 /* middle */ 6070 for (i = 0; i < k - 1; ++i) { 6071 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6072 for (n = 0; n < k - 1; ++n) 6073 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6074 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6075 } 6076 /* top */ 6077 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6078 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6079 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6080 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6081 } 6082 6083 /* Top Slice */ 6084 /* bottom */ 6085 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6086 for (o = oetf; o < oetr; ++o) 6087 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6088 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6089 /* middle */ 6090 for (i = 0; i < k - 1; ++i) { 6091 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6092 for (n = 0; n < k - 1; ++n) 6093 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6094 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6095 } 6096 /* top */ 6097 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6098 for (o = oetl - 1; o >= oetb; --o) 6099 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6100 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6101 6102 foffset = offset; 6103 } else { 6104 PetscInt dof; 6105 6106 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6107 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6108 foffset = offset; 6109 } 6110 break; 6111 default: 6112 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6113 } 6114 } 6115 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6116 /* Check permutation */ 6117 { 6118 PetscInt *check; 6119 6120 PetscCall(PetscMalloc1(size, &check)); 6121 for (i = 0; i < size; ++i) { 6122 check[i] = -1; 6123 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6124 } 6125 for (i = 0; i < size; ++i) check[perm[i]] = i; 6126 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6127 PetscCall(PetscFree(check)); 6128 } 6129 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6130 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6131 PetscInt *loc_perm; 6132 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6133 for (PetscInt i = 0; i < size; i++) { 6134 loc_perm[i] = perm[i]; 6135 loc_perm[size + i] = size + perm[i]; 6136 } 6137 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6138 } 6139 } 6140 PetscFunctionReturn(PETSC_SUCCESS); 6141 } 6142 6143 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6144 { 6145 PetscDS prob; 6146 PetscInt depth, Nf, h; 6147 DMLabel label; 6148 6149 PetscFunctionBeginHot; 6150 PetscCall(DMGetDS(dm, &prob)); 6151 Nf = prob->Nf; 6152 label = dm->depthLabel; 6153 *dspace = NULL; 6154 if (field < Nf) { 6155 PetscObject disc = prob->disc[field]; 6156 6157 if (disc->classid == PETSCFE_CLASSID) { 6158 PetscDualSpace dsp; 6159 6160 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6161 PetscCall(DMLabelGetNumValues(label, &depth)); 6162 PetscCall(DMLabelGetValue(label, point, &h)); 6163 h = depth - 1 - h; 6164 if (h) { 6165 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6166 } else { 6167 *dspace = dsp; 6168 } 6169 } 6170 } 6171 PetscFunctionReturn(PETSC_SUCCESS); 6172 } 6173 6174 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6175 { 6176 PetscScalar *array; 6177 const PetscScalar *vArray; 6178 const PetscInt *cone, *coneO; 6179 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6180 6181 PetscFunctionBeginHot; 6182 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6183 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6184 PetscCall(DMPlexGetCone(dm, point, &cone)); 6185 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6186 if (!values || !*values) { 6187 if ((point >= pStart) && (point < pEnd)) { 6188 PetscInt dof; 6189 6190 PetscCall(PetscSectionGetDof(section, point, &dof)); 6191 size += dof; 6192 } 6193 for (p = 0; p < numPoints; ++p) { 6194 const PetscInt cp = cone[p]; 6195 PetscInt dof; 6196 6197 if ((cp < pStart) || (cp >= pEnd)) continue; 6198 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6199 size += dof; 6200 } 6201 if (!values) { 6202 if (csize) *csize = size; 6203 PetscFunctionReturn(PETSC_SUCCESS); 6204 } 6205 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6206 } else { 6207 array = *values; 6208 } 6209 size = 0; 6210 PetscCall(VecGetArrayRead(v, &vArray)); 6211 if ((point >= pStart) && (point < pEnd)) { 6212 PetscInt dof, off, d; 6213 const PetscScalar *varr; 6214 6215 PetscCall(PetscSectionGetDof(section, point, &dof)); 6216 PetscCall(PetscSectionGetOffset(section, point, &off)); 6217 varr = PetscSafePointerPlusOffset(vArray, off); 6218 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6219 size += dof; 6220 } 6221 for (p = 0; p < numPoints; ++p) { 6222 const PetscInt cp = cone[p]; 6223 PetscInt o = coneO[p]; 6224 PetscInt dof, off, d; 6225 const PetscScalar *varr; 6226 6227 if ((cp < pStart) || (cp >= pEnd)) continue; 6228 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6229 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6230 varr = PetscSafePointerPlusOffset(vArray, off); 6231 if (o >= 0) { 6232 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6233 } else { 6234 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6235 } 6236 size += dof; 6237 } 6238 PetscCall(VecRestoreArrayRead(v, &vArray)); 6239 if (!*values) { 6240 if (csize) *csize = size; 6241 *values = array; 6242 } else { 6243 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6244 *csize = size; 6245 } 6246 PetscFunctionReturn(PETSC_SUCCESS); 6247 } 6248 6249 /* Compress out points not in the section */ 6250 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6251 { 6252 const PetscInt np = *numPoints; 6253 PetscInt pStart, pEnd, p, q; 6254 6255 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6256 for (p = 0, q = 0; p < np; ++p) { 6257 const PetscInt r = points[p * 2]; 6258 if ((r >= pStart) && (r < pEnd)) { 6259 points[q * 2] = r; 6260 points[q * 2 + 1] = points[p * 2 + 1]; 6261 ++q; 6262 } 6263 } 6264 *numPoints = q; 6265 return PETSC_SUCCESS; 6266 } 6267 6268 /* Compressed closure does not apply closure permutation */ 6269 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6270 { 6271 const PetscInt *cla = NULL; 6272 PetscInt np, *pts = NULL; 6273 6274 PetscFunctionBeginHot; 6275 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6276 if (!ornt && *clPoints) { 6277 PetscInt dof, off; 6278 6279 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6280 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6281 PetscCall(ISGetIndices(*clPoints, &cla)); 6282 np = dof / 2; 6283 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6284 } else { 6285 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6286 PetscCall(CompressPoints_Private(section, &np, pts)); 6287 } 6288 *numPoints = np; 6289 *points = pts; 6290 *clp = cla; 6291 PetscFunctionReturn(PETSC_SUCCESS); 6292 } 6293 6294 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6295 { 6296 PetscFunctionBeginHot; 6297 if (!*clPoints) { 6298 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6299 } else { 6300 PetscCall(ISRestoreIndices(*clPoints, clp)); 6301 } 6302 *numPoints = 0; 6303 *points = NULL; 6304 *clSec = NULL; 6305 *clPoints = NULL; 6306 *clp = NULL; 6307 PetscFunctionReturn(PETSC_SUCCESS); 6308 } 6309 6310 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6311 { 6312 PetscInt offset = 0, p; 6313 const PetscInt **perms = NULL; 6314 const PetscScalar **flips = NULL; 6315 6316 PetscFunctionBeginHot; 6317 *size = 0; 6318 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6319 for (p = 0; p < numPoints; p++) { 6320 const PetscInt point = points[2 * p]; 6321 const PetscInt *perm = perms ? perms[p] : NULL; 6322 const PetscScalar *flip = flips ? flips[p] : NULL; 6323 PetscInt dof, off, d; 6324 const PetscScalar *varr; 6325 6326 PetscCall(PetscSectionGetDof(section, point, &dof)); 6327 PetscCall(PetscSectionGetOffset(section, point, &off)); 6328 varr = PetscSafePointerPlusOffset(vArray, off); 6329 if (clperm) { 6330 if (perm) { 6331 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6332 } else { 6333 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6334 } 6335 if (flip) { 6336 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6337 } 6338 } else { 6339 if (perm) { 6340 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6341 } else { 6342 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6343 } 6344 if (flip) { 6345 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6346 } 6347 } 6348 offset += dof; 6349 } 6350 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6351 *size = offset; 6352 PetscFunctionReturn(PETSC_SUCCESS); 6353 } 6354 6355 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[]) 6356 { 6357 PetscInt offset = 0, f; 6358 6359 PetscFunctionBeginHot; 6360 *size = 0; 6361 for (f = 0; f < numFields; ++f) { 6362 PetscInt p; 6363 const PetscInt **perms = NULL; 6364 const PetscScalar **flips = NULL; 6365 6366 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6367 for (p = 0; p < numPoints; p++) { 6368 const PetscInt point = points[2 * p]; 6369 PetscInt fdof, foff, b; 6370 const PetscScalar *varr; 6371 const PetscInt *perm = perms ? perms[p] : NULL; 6372 const PetscScalar *flip = flips ? flips[p] : NULL; 6373 6374 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6375 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6376 varr = &vArray[foff]; 6377 if (clperm) { 6378 if (perm) { 6379 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6380 } else { 6381 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6382 } 6383 if (flip) { 6384 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6385 } 6386 } else { 6387 if (perm) { 6388 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6389 } else { 6390 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6391 } 6392 if (flip) { 6393 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6394 } 6395 } 6396 offset += fdof; 6397 } 6398 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6399 } 6400 *size = offset; 6401 PetscFunctionReturn(PETSC_SUCCESS); 6402 } 6403 6404 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6405 { 6406 PetscSection clSection; 6407 IS clPoints; 6408 PetscInt *points = NULL; 6409 const PetscInt *clp, *perm = NULL; 6410 PetscInt depth, numFields, numPoints, asize; 6411 6412 PetscFunctionBeginHot; 6413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6414 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6415 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6416 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6417 PetscCall(DMPlexGetDepth(dm, &depth)); 6418 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6419 if (depth == 1 && numFields < 2) { 6420 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6421 PetscFunctionReturn(PETSC_SUCCESS); 6422 } 6423 /* Get points */ 6424 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6425 /* Get sizes */ 6426 asize = 0; 6427 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6428 PetscInt dof; 6429 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6430 asize += dof; 6431 } 6432 if (values) { 6433 const PetscScalar *vArray; 6434 PetscInt size; 6435 6436 if (*values) { 6437 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); 6438 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6439 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6440 PetscCall(VecGetArrayRead(v, &vArray)); 6441 /* Get values */ 6442 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6443 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6444 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6445 /* Cleanup array */ 6446 PetscCall(VecRestoreArrayRead(v, &vArray)); 6447 } 6448 if (csize) *csize = asize; 6449 /* Cleanup points */ 6450 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6451 PetscFunctionReturn(PETSC_SUCCESS); 6452 } 6453 6454 /*@C 6455 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6456 6457 Not collective 6458 6459 Input Parameters: 6460 + dm - The `DM` 6461 . section - The section describing the layout in `v`, or `NULL` to use the default section 6462 . v - The local vector 6463 - point - The point in the `DM` 6464 6465 Input/Output Parameters: 6466 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6467 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6468 if the user provided `NULL`, it is a borrowed array and should not be freed 6469 6470 Level: intermediate 6471 6472 Notes: 6473 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6474 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6475 assembly function, and a user may already have allocated storage for this operation. 6476 6477 A typical use could be 6478 .vb 6479 values = NULL; 6480 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6481 for (cl = 0; cl < clSize; ++cl) { 6482 <Compute on closure> 6483 } 6484 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6485 .ve 6486 or 6487 .vb 6488 PetscMalloc1(clMaxSize, &values); 6489 for (p = pStart; p < pEnd; ++p) { 6490 clSize = clMaxSize; 6491 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6492 for (cl = 0; cl < clSize; ++cl) { 6493 <Compute on closure> 6494 } 6495 } 6496 PetscFree(values); 6497 .ve 6498 6499 Fortran Notes: 6500 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6501 6502 `values` must be declared with 6503 .vb 6504 PetscScalar,dimension(:),pointer :: values 6505 .ve 6506 and it will be allocated internally by PETSc to hold the values returned 6507 6508 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6509 @*/ 6510 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6511 { 6512 PetscFunctionBeginHot; 6513 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6514 PetscFunctionReturn(PETSC_SUCCESS); 6515 } 6516 6517 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6518 { 6519 DMLabel depthLabel; 6520 PetscSection clSection; 6521 IS clPoints; 6522 PetscScalar *array; 6523 const PetscScalar *vArray; 6524 PetscInt *points = NULL; 6525 const PetscInt *clp, *perm = NULL; 6526 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6527 6528 PetscFunctionBeginHot; 6529 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6530 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6531 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6532 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6533 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6534 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6535 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6536 if (mdepth == 1 && numFields < 2) { 6537 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6538 PetscFunctionReturn(PETSC_SUCCESS); 6539 } 6540 /* Get points */ 6541 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6542 for (clsize = 0, p = 0; p < Np; p++) { 6543 PetscInt dof; 6544 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6545 clsize += dof; 6546 } 6547 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6548 /* Filter points */ 6549 for (p = 0; p < numPoints * 2; p += 2) { 6550 PetscInt dep; 6551 6552 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6553 if (dep != depth) continue; 6554 points[Np * 2 + 0] = points[p]; 6555 points[Np * 2 + 1] = points[p + 1]; 6556 ++Np; 6557 } 6558 /* Get array */ 6559 if (!values || !*values) { 6560 PetscInt asize = 0, dof; 6561 6562 for (p = 0; p < Np * 2; p += 2) { 6563 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6564 asize += dof; 6565 } 6566 if (!values) { 6567 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6568 if (csize) *csize = asize; 6569 PetscFunctionReturn(PETSC_SUCCESS); 6570 } 6571 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6572 } else { 6573 array = *values; 6574 } 6575 PetscCall(VecGetArrayRead(v, &vArray)); 6576 /* Get values */ 6577 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6578 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6579 /* Cleanup points */ 6580 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6581 /* Cleanup array */ 6582 PetscCall(VecRestoreArrayRead(v, &vArray)); 6583 if (!*values) { 6584 if (csize) *csize = size; 6585 *values = array; 6586 } else { 6587 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6588 *csize = size; 6589 } 6590 PetscFunctionReturn(PETSC_SUCCESS); 6591 } 6592 6593 /*@C 6594 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6595 6596 Not collective 6597 6598 Input Parameters: 6599 + dm - The `DM` 6600 . section - The section describing the layout in `v`, or `NULL` to use the default section 6601 . v - The local vector 6602 . point - The point in the `DM` 6603 . csize - The number of values in the closure, or `NULL` 6604 - values - The array of values 6605 6606 Level: intermediate 6607 6608 Note: 6609 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6610 6611 Fortran Note: 6612 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6613 6614 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6615 @*/ 6616 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6617 { 6618 PetscInt size = 0; 6619 6620 PetscFunctionBegin; 6621 /* Should work without recalculating size */ 6622 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6623 *values = NULL; 6624 PetscFunctionReturn(PETSC_SUCCESS); 6625 } 6626 6627 static inline void add(PetscScalar *x, PetscScalar y) 6628 { 6629 *x += y; 6630 } 6631 static inline void insert(PetscScalar *x, PetscScalar y) 6632 { 6633 *x = y; 6634 } 6635 6636 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[]) 6637 { 6638 PetscInt cdof; /* The number of constraints on this point */ 6639 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6640 PetscScalar *a; 6641 PetscInt off, cind = 0, k; 6642 6643 PetscFunctionBegin; 6644 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6645 PetscCall(PetscSectionGetOffset(section, point, &off)); 6646 a = &array[off]; 6647 if (!cdof || setBC) { 6648 if (clperm) { 6649 if (perm) { 6650 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6651 } else { 6652 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6653 } 6654 } else { 6655 if (perm) { 6656 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6657 } else { 6658 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6659 } 6660 } 6661 } else { 6662 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6663 if (clperm) { 6664 if (perm) { 6665 for (k = 0; k < dof; ++k) { 6666 if ((cind < cdof) && (k == cdofs[cind])) { 6667 ++cind; 6668 continue; 6669 } 6670 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6671 } 6672 } else { 6673 for (k = 0; k < dof; ++k) { 6674 if ((cind < cdof) && (k == cdofs[cind])) { 6675 ++cind; 6676 continue; 6677 } 6678 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6679 } 6680 } 6681 } else { 6682 if (perm) { 6683 for (k = 0; k < dof; ++k) { 6684 if ((cind < cdof) && (k == cdofs[cind])) { 6685 ++cind; 6686 continue; 6687 } 6688 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6689 } 6690 } else { 6691 for (k = 0; k < dof; ++k) { 6692 if ((cind < cdof) && (k == cdofs[cind])) { 6693 ++cind; 6694 continue; 6695 } 6696 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6697 } 6698 } 6699 } 6700 } 6701 PetscFunctionReturn(PETSC_SUCCESS); 6702 } 6703 6704 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[]) 6705 { 6706 PetscInt cdof; /* The number of constraints on this point */ 6707 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6708 PetscScalar *a; 6709 PetscInt off, cind = 0, k; 6710 6711 PetscFunctionBegin; 6712 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6713 PetscCall(PetscSectionGetOffset(section, point, &off)); 6714 a = &array[off]; 6715 if (cdof) { 6716 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6717 if (clperm) { 6718 if (perm) { 6719 for (k = 0; k < dof; ++k) { 6720 if ((cind < cdof) && (k == cdofs[cind])) { 6721 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6722 cind++; 6723 } 6724 } 6725 } else { 6726 for (k = 0; k < dof; ++k) { 6727 if ((cind < cdof) && (k == cdofs[cind])) { 6728 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6729 cind++; 6730 } 6731 } 6732 } 6733 } else { 6734 if (perm) { 6735 for (k = 0; k < dof; ++k) { 6736 if ((cind < cdof) && (k == cdofs[cind])) { 6737 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6738 cind++; 6739 } 6740 } 6741 } else { 6742 for (k = 0; k < dof; ++k) { 6743 if ((cind < cdof) && (k == cdofs[cind])) { 6744 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6745 cind++; 6746 } 6747 } 6748 } 6749 } 6750 } 6751 PetscFunctionReturn(PETSC_SUCCESS); 6752 } 6753 6754 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[]) 6755 { 6756 PetscScalar *a; 6757 PetscInt fdof, foff, fcdof, foffset = *offset; 6758 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6759 PetscInt cind = 0, b; 6760 6761 PetscFunctionBegin; 6762 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6763 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6764 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6765 a = &array[foff]; 6766 if (!fcdof || setBC) { 6767 if (clperm) { 6768 if (perm) { 6769 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6770 } else { 6771 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6772 } 6773 } else { 6774 if (perm) { 6775 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6776 } else { 6777 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6778 } 6779 } 6780 } else { 6781 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6782 if (clperm) { 6783 if (perm) { 6784 for (b = 0; b < fdof; b++) { 6785 if ((cind < fcdof) && (b == fcdofs[cind])) { 6786 ++cind; 6787 continue; 6788 } 6789 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6790 } 6791 } else { 6792 for (b = 0; b < fdof; b++) { 6793 if ((cind < fcdof) && (b == fcdofs[cind])) { 6794 ++cind; 6795 continue; 6796 } 6797 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6798 } 6799 } 6800 } else { 6801 if (perm) { 6802 for (b = 0; b < fdof; b++) { 6803 if ((cind < fcdof) && (b == fcdofs[cind])) { 6804 ++cind; 6805 continue; 6806 } 6807 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6808 } 6809 } else { 6810 for (b = 0; b < fdof; b++) { 6811 if ((cind < fcdof) && (b == fcdofs[cind])) { 6812 ++cind; 6813 continue; 6814 } 6815 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6816 } 6817 } 6818 } 6819 } 6820 *offset += fdof; 6821 PetscFunctionReturn(PETSC_SUCCESS); 6822 } 6823 6824 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[]) 6825 { 6826 PetscScalar *a; 6827 PetscInt fdof, foff, fcdof, foffset = *offset; 6828 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6829 PetscInt Nc, cind = 0, ncind = 0, b; 6830 PetscBool ncSet, fcSet; 6831 6832 PetscFunctionBegin; 6833 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6834 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6835 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6836 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6837 a = &array[foff]; 6838 if (fcdof) { 6839 /* We just override fcdof and fcdofs with Ncc and comps */ 6840 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6841 if (clperm) { 6842 if (perm) { 6843 if (comps) { 6844 for (b = 0; b < fdof; b++) { 6845 ncSet = fcSet = PETSC_FALSE; 6846 if (b % Nc == comps[ncind]) { 6847 ncind = (ncind + 1) % Ncc; 6848 ncSet = PETSC_TRUE; 6849 } 6850 if ((cind < fcdof) && (b == fcdofs[cind])) { 6851 ++cind; 6852 fcSet = PETSC_TRUE; 6853 } 6854 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6855 } 6856 } else { 6857 for (b = 0; b < fdof; b++) { 6858 if ((cind < fcdof) && (b == fcdofs[cind])) { 6859 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6860 ++cind; 6861 } 6862 } 6863 } 6864 } else { 6865 if (comps) { 6866 for (b = 0; b < fdof; b++) { 6867 ncSet = fcSet = PETSC_FALSE; 6868 if (b % Nc == comps[ncind]) { 6869 ncind = (ncind + 1) % Ncc; 6870 ncSet = PETSC_TRUE; 6871 } 6872 if ((cind < fcdof) && (b == fcdofs[cind])) { 6873 ++cind; 6874 fcSet = PETSC_TRUE; 6875 } 6876 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6877 } 6878 } else { 6879 for (b = 0; b < fdof; b++) { 6880 if ((cind < fcdof) && (b == fcdofs[cind])) { 6881 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6882 ++cind; 6883 } 6884 } 6885 } 6886 } 6887 } else { 6888 if (perm) { 6889 if (comps) { 6890 for (b = 0; b < fdof; b++) { 6891 ncSet = fcSet = PETSC_FALSE; 6892 if (b % Nc == comps[ncind]) { 6893 ncind = (ncind + 1) % Ncc; 6894 ncSet = PETSC_TRUE; 6895 } 6896 if ((cind < fcdof) && (b == fcdofs[cind])) { 6897 ++cind; 6898 fcSet = PETSC_TRUE; 6899 } 6900 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6901 } 6902 } else { 6903 for (b = 0; b < fdof; b++) { 6904 if ((cind < fcdof) && (b == fcdofs[cind])) { 6905 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6906 ++cind; 6907 } 6908 } 6909 } 6910 } else { 6911 if (comps) { 6912 for (b = 0; b < fdof; b++) { 6913 ncSet = fcSet = PETSC_FALSE; 6914 if (b % Nc == comps[ncind]) { 6915 ncind = (ncind + 1) % Ncc; 6916 ncSet = PETSC_TRUE; 6917 } 6918 if ((cind < fcdof) && (b == fcdofs[cind])) { 6919 ++cind; 6920 fcSet = PETSC_TRUE; 6921 } 6922 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6923 } 6924 } else { 6925 for (b = 0; b < fdof; b++) { 6926 if ((cind < fcdof) && (b == fcdofs[cind])) { 6927 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6928 ++cind; 6929 } 6930 } 6931 } 6932 } 6933 } 6934 } 6935 *offset += fdof; 6936 PetscFunctionReturn(PETSC_SUCCESS); 6937 } 6938 6939 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6940 { 6941 PetscScalar *array; 6942 const PetscInt *cone, *coneO; 6943 PetscInt pStart, pEnd, p, numPoints, off, dof; 6944 6945 PetscFunctionBeginHot; 6946 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6947 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6948 PetscCall(DMPlexGetCone(dm, point, &cone)); 6949 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6950 PetscCall(VecGetArray(v, &array)); 6951 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6952 const PetscInt cp = !p ? point : cone[p - 1]; 6953 const PetscInt o = !p ? 0 : coneO[p - 1]; 6954 6955 if ((cp < pStart) || (cp >= pEnd)) { 6956 dof = 0; 6957 continue; 6958 } 6959 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6960 /* ADD_VALUES */ 6961 { 6962 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6963 PetscScalar *a; 6964 PetscInt cdof, coff, cind = 0, k; 6965 6966 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6967 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6968 a = &array[coff]; 6969 if (!cdof) { 6970 if (o >= 0) { 6971 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6972 } else { 6973 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6974 } 6975 } else { 6976 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6977 if (o >= 0) { 6978 for (k = 0; k < dof; ++k) { 6979 if ((cind < cdof) && (k == cdofs[cind])) { 6980 ++cind; 6981 continue; 6982 } 6983 a[k] += values[off + k]; 6984 } 6985 } else { 6986 for (k = 0; k < dof; ++k) { 6987 if ((cind < cdof) && (k == cdofs[cind])) { 6988 ++cind; 6989 continue; 6990 } 6991 a[k] += values[off + dof - k - 1]; 6992 } 6993 } 6994 } 6995 } 6996 } 6997 PetscCall(VecRestoreArray(v, &array)); 6998 PetscFunctionReturn(PETSC_SUCCESS); 6999 } 7000 7001 /*@C 7002 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7003 7004 Not collective 7005 7006 Input Parameters: 7007 + dm - The `DM` 7008 . section - The section describing the layout in `v`, or `NULL` to use the default section 7009 . v - The local vector 7010 . point - The point in the `DM` 7011 . values - The array of values 7012 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7013 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7014 7015 Level: intermediate 7016 7017 Note: 7018 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7019 7020 Fortran Note: 7021 `values` must be declared with 7022 .vb 7023 PetscScalar,dimension(:),pointer :: values 7024 .ve 7025 7026 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7027 @*/ 7028 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7029 { 7030 PetscSection clSection; 7031 IS clPoints; 7032 PetscScalar *array; 7033 PetscInt *points = NULL; 7034 const PetscInt *clp, *clperm = NULL; 7035 PetscInt depth, numFields, numPoints, p, clsize; 7036 7037 PetscFunctionBeginHot; 7038 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7039 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7040 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7041 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7042 PetscCall(DMPlexGetDepth(dm, &depth)); 7043 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7044 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7045 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7046 PetscFunctionReturn(PETSC_SUCCESS); 7047 } 7048 /* Get points */ 7049 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7050 for (clsize = 0, p = 0; p < numPoints; p++) { 7051 PetscInt dof; 7052 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7053 clsize += dof; 7054 } 7055 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7056 /* Get array */ 7057 PetscCall(VecGetArray(v, &array)); 7058 /* Get values */ 7059 if (numFields > 0) { 7060 PetscInt offset = 0, f; 7061 for (f = 0; f < numFields; ++f) { 7062 const PetscInt **perms = NULL; 7063 const PetscScalar **flips = NULL; 7064 7065 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7066 switch (mode) { 7067 case INSERT_VALUES: 7068 for (p = 0; p < numPoints; p++) { 7069 const PetscInt point = points[2 * p]; 7070 const PetscInt *perm = perms ? perms[p] : NULL; 7071 const PetscScalar *flip = flips ? flips[p] : NULL; 7072 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7073 } 7074 break; 7075 case INSERT_ALL_VALUES: 7076 for (p = 0; p < numPoints; p++) { 7077 const PetscInt point = points[2 * p]; 7078 const PetscInt *perm = perms ? perms[p] : NULL; 7079 const PetscScalar *flip = flips ? flips[p] : NULL; 7080 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7081 } 7082 break; 7083 case INSERT_BC_VALUES: 7084 for (p = 0; p < numPoints; p++) { 7085 const PetscInt point = points[2 * p]; 7086 const PetscInt *perm = perms ? perms[p] : NULL; 7087 const PetscScalar *flip = flips ? flips[p] : NULL; 7088 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7089 } 7090 break; 7091 case ADD_VALUES: 7092 for (p = 0; p < numPoints; p++) { 7093 const PetscInt point = points[2 * p]; 7094 const PetscInt *perm = perms ? perms[p] : NULL; 7095 const PetscScalar *flip = flips ? flips[p] : NULL; 7096 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7097 } 7098 break; 7099 case ADD_ALL_VALUES: 7100 for (p = 0; p < numPoints; p++) { 7101 const PetscInt point = points[2 * p]; 7102 const PetscInt *perm = perms ? perms[p] : NULL; 7103 const PetscScalar *flip = flips ? flips[p] : NULL; 7104 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7105 } 7106 break; 7107 case ADD_BC_VALUES: 7108 for (p = 0; p < numPoints; p++) { 7109 const PetscInt point = points[2 * p]; 7110 const PetscInt *perm = perms ? perms[p] : NULL; 7111 const PetscScalar *flip = flips ? flips[p] : NULL; 7112 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7113 } 7114 break; 7115 default: 7116 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7117 } 7118 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7119 } 7120 } else { 7121 PetscInt dof, off; 7122 const PetscInt **perms = NULL; 7123 const PetscScalar **flips = NULL; 7124 7125 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7126 switch (mode) { 7127 case INSERT_VALUES: 7128 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7129 const PetscInt point = points[2 * p]; 7130 const PetscInt *perm = perms ? perms[p] : NULL; 7131 const PetscScalar *flip = flips ? flips[p] : NULL; 7132 PetscCall(PetscSectionGetDof(section, point, &dof)); 7133 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7134 } 7135 break; 7136 case INSERT_ALL_VALUES: 7137 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7138 const PetscInt point = points[2 * p]; 7139 const PetscInt *perm = perms ? perms[p] : NULL; 7140 const PetscScalar *flip = flips ? flips[p] : NULL; 7141 PetscCall(PetscSectionGetDof(section, point, &dof)); 7142 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7143 } 7144 break; 7145 case INSERT_BC_VALUES: 7146 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7147 const PetscInt point = points[2 * p]; 7148 const PetscInt *perm = perms ? perms[p] : NULL; 7149 const PetscScalar *flip = flips ? flips[p] : NULL; 7150 PetscCall(PetscSectionGetDof(section, point, &dof)); 7151 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7152 } 7153 break; 7154 case ADD_VALUES: 7155 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7156 const PetscInt point = points[2 * p]; 7157 const PetscInt *perm = perms ? perms[p] : NULL; 7158 const PetscScalar *flip = flips ? flips[p] : NULL; 7159 PetscCall(PetscSectionGetDof(section, point, &dof)); 7160 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7161 } 7162 break; 7163 case ADD_ALL_VALUES: 7164 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7165 const PetscInt point = points[2 * p]; 7166 const PetscInt *perm = perms ? perms[p] : NULL; 7167 const PetscScalar *flip = flips ? flips[p] : NULL; 7168 PetscCall(PetscSectionGetDof(section, point, &dof)); 7169 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7170 } 7171 break; 7172 case ADD_BC_VALUES: 7173 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7174 const PetscInt point = points[2 * p]; 7175 const PetscInt *perm = perms ? perms[p] : NULL; 7176 const PetscScalar *flip = flips ? flips[p] : NULL; 7177 PetscCall(PetscSectionGetDof(section, point, &dof)); 7178 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7179 } 7180 break; 7181 default: 7182 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7183 } 7184 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7185 } 7186 /* Cleanup points */ 7187 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7188 /* Cleanup array */ 7189 PetscCall(VecRestoreArray(v, &array)); 7190 PetscFunctionReturn(PETSC_SUCCESS); 7191 } 7192 7193 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7194 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7195 { 7196 PetscFunctionBegin; 7197 *contains = PETSC_TRUE; 7198 if (label) { 7199 PetscInt fdof; 7200 7201 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7202 if (!*contains) { 7203 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7204 *offset += fdof; 7205 PetscFunctionReturn(PETSC_SUCCESS); 7206 } 7207 } 7208 PetscFunctionReturn(PETSC_SUCCESS); 7209 } 7210 7211 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7212 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) 7213 { 7214 PetscSection clSection; 7215 IS clPoints; 7216 PetscScalar *array; 7217 PetscInt *points = NULL; 7218 const PetscInt *clp; 7219 PetscInt numFields, numPoints, p; 7220 PetscInt offset = 0, f; 7221 7222 PetscFunctionBeginHot; 7223 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7224 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7225 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7226 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7227 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7228 /* Get points */ 7229 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7230 /* Get array */ 7231 PetscCall(VecGetArray(v, &array)); 7232 /* Get values */ 7233 for (f = 0; f < numFields; ++f) { 7234 const PetscInt **perms = NULL; 7235 const PetscScalar **flips = NULL; 7236 PetscBool contains; 7237 7238 if (!fieldActive[f]) { 7239 for (p = 0; p < numPoints * 2; p += 2) { 7240 PetscInt fdof; 7241 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7242 offset += fdof; 7243 } 7244 continue; 7245 } 7246 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7247 switch (mode) { 7248 case INSERT_VALUES: 7249 for (p = 0; p < numPoints; p++) { 7250 const PetscInt point = points[2 * p]; 7251 const PetscInt *perm = perms ? perms[p] : NULL; 7252 const PetscScalar *flip = flips ? flips[p] : NULL; 7253 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7254 if (!contains) continue; 7255 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7256 } 7257 break; 7258 case INSERT_ALL_VALUES: 7259 for (p = 0; p < numPoints; p++) { 7260 const PetscInt point = points[2 * p]; 7261 const PetscInt *perm = perms ? perms[p] : NULL; 7262 const PetscScalar *flip = flips ? flips[p] : NULL; 7263 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7264 if (!contains) continue; 7265 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7266 } 7267 break; 7268 case INSERT_BC_VALUES: 7269 for (p = 0; p < numPoints; p++) { 7270 const PetscInt point = points[2 * p]; 7271 const PetscInt *perm = perms ? perms[p] : NULL; 7272 const PetscScalar *flip = flips ? flips[p] : NULL; 7273 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7274 if (!contains) continue; 7275 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7276 } 7277 break; 7278 case ADD_VALUES: 7279 for (p = 0; p < numPoints; p++) { 7280 const PetscInt point = points[2 * p]; 7281 const PetscInt *perm = perms ? perms[p] : NULL; 7282 const PetscScalar *flip = flips ? flips[p] : NULL; 7283 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7284 if (!contains) continue; 7285 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7286 } 7287 break; 7288 case ADD_ALL_VALUES: 7289 for (p = 0; p < numPoints; p++) { 7290 const PetscInt point = points[2 * p]; 7291 const PetscInt *perm = perms ? perms[p] : NULL; 7292 const PetscScalar *flip = flips ? flips[p] : NULL; 7293 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7294 if (!contains) continue; 7295 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7296 } 7297 break; 7298 default: 7299 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7300 } 7301 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7302 } 7303 /* Cleanup points */ 7304 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7305 /* Cleanup array */ 7306 PetscCall(VecRestoreArray(v, &array)); 7307 PetscFunctionReturn(PETSC_SUCCESS); 7308 } 7309 7310 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7311 { 7312 PetscMPIInt rank; 7313 PetscInt i, j; 7314 7315 PetscFunctionBegin; 7316 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7317 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7318 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7319 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7320 numCIndices = numCIndices ? numCIndices : numRIndices; 7321 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7322 for (i = 0; i < numRIndices; i++) { 7323 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7324 for (j = 0; j < numCIndices; j++) { 7325 #if defined(PETSC_USE_COMPLEX) 7326 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7327 #else 7328 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7329 #endif 7330 } 7331 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7332 } 7333 PetscFunctionReturn(PETSC_SUCCESS); 7334 } 7335 7336 /* 7337 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7338 7339 Input Parameters: 7340 + section - The section for this data layout 7341 . islocal - Is the section (and thus indices being requested) local or global? 7342 . point - The point contributing dofs with these indices 7343 . off - The global offset of this point 7344 . loff - The local offset of each field 7345 . setBC - The flag determining whether to include indices of boundary values 7346 . perm - A permutation of the dofs on this point, or NULL 7347 - indperm - A permutation of the entire indices array, or NULL 7348 7349 Output Parameter: 7350 . indices - Indices for dofs on this point 7351 7352 Level: developer 7353 7354 Note: The indices could be local or global, depending on the value of 'off'. 7355 */ 7356 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7357 { 7358 PetscInt dof; /* The number of unknowns on this point */ 7359 PetscInt cdof; /* The number of constraints on this point */ 7360 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7361 PetscInt cind = 0, k; 7362 7363 PetscFunctionBegin; 7364 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7365 PetscCall(PetscSectionGetDof(section, point, &dof)); 7366 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7367 if (!cdof || setBC) { 7368 for (k = 0; k < dof; ++k) { 7369 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7370 const PetscInt ind = indperm ? indperm[preind] : preind; 7371 7372 indices[ind] = off + k; 7373 } 7374 } else { 7375 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7376 for (k = 0; k < dof; ++k) { 7377 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7378 const PetscInt ind = indperm ? indperm[preind] : preind; 7379 7380 if ((cind < cdof) && (k == cdofs[cind])) { 7381 /* Insert check for returning constrained indices */ 7382 indices[ind] = -(off + k + 1); 7383 ++cind; 7384 } else { 7385 indices[ind] = off + k - (islocal ? 0 : cind); 7386 } 7387 } 7388 } 7389 *loff += dof; 7390 PetscFunctionReturn(PETSC_SUCCESS); 7391 } 7392 7393 /* 7394 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7395 7396 Input Parameters: 7397 + section - a section (global or local) 7398 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7399 . point - point within section 7400 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7401 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7402 . setBC - identify constrained (boundary condition) points via involution. 7403 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7404 . permsoff - offset 7405 - indperm - index permutation 7406 7407 Output Parameter: 7408 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7409 . indices - array to hold indices (as defined by section) of each dof associated with point 7410 7411 Notes: 7412 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7413 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7414 in the local vector. 7415 7416 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7417 significant). It is invalid to call with a global section and setBC=true. 7418 7419 Developer Note: 7420 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7421 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7422 offset could be obtained from the section instead of passing it explicitly as we do now. 7423 7424 Example: 7425 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7426 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7427 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7428 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. 7429 7430 Level: developer 7431 */ 7432 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[]) 7433 { 7434 PetscInt numFields, foff, f; 7435 7436 PetscFunctionBegin; 7437 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7438 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7439 for (f = 0, foff = 0; f < numFields; ++f) { 7440 PetscInt fdof, cfdof; 7441 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7442 PetscInt cind = 0, b; 7443 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7444 7445 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7446 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7447 if (!cfdof || setBC) { 7448 for (b = 0; b < fdof; ++b) { 7449 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7450 const PetscInt ind = indperm ? indperm[preind] : preind; 7451 7452 indices[ind] = off + foff + b; 7453 } 7454 } else { 7455 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7456 for (b = 0; b < fdof; ++b) { 7457 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7458 const PetscInt ind = indperm ? indperm[preind] : preind; 7459 7460 if ((cind < cfdof) && (b == fcdofs[cind])) { 7461 indices[ind] = -(off + foff + b + 1); 7462 ++cind; 7463 } else { 7464 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7465 } 7466 } 7467 } 7468 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7469 foffs[f] += fdof; 7470 } 7471 PetscFunctionReturn(PETSC_SUCCESS); 7472 } 7473 7474 /* 7475 This version believes the globalSection offsets for each field, rather than just the point offset 7476 7477 . foffs - The offset into 'indices' for each field, since it is segregated by field 7478 7479 Notes: 7480 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7481 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7482 */ 7483 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7484 { 7485 PetscInt numFields, foff, f; 7486 7487 PetscFunctionBegin; 7488 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7489 for (f = 0; f < numFields; ++f) { 7490 PetscInt fdof, cfdof; 7491 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7492 PetscInt cind = 0, b; 7493 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7494 7495 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7496 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7497 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7498 if (!cfdof) { 7499 for (b = 0; b < fdof; ++b) { 7500 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7501 const PetscInt ind = indperm ? indperm[preind] : preind; 7502 7503 indices[ind] = foff + b; 7504 } 7505 } else { 7506 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7507 for (b = 0; b < fdof; ++b) { 7508 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7509 const PetscInt ind = indperm ? indperm[preind] : preind; 7510 7511 if ((cind < cfdof) && (b == fcdofs[cind])) { 7512 indices[ind] = -(foff + b + 1); 7513 ++cind; 7514 } else { 7515 indices[ind] = foff + b - cind; 7516 } 7517 } 7518 } 7519 foffs[f] += fdof; 7520 } 7521 PetscFunctionReturn(PETSC_SUCCESS); 7522 } 7523 7524 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7525 { 7526 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7527 7528 PetscFunctionBegin; 7529 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7530 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7531 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7532 for (PetscInt p = 0; p < nPoints; p++) { 7533 PetscInt b = pnts[2 * p]; 7534 PetscInt bSecDof = 0, bOff; 7535 PetscInt cSecDof = 0; 7536 PetscSection indices_section; 7537 7538 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7539 if (!bSecDof) continue; 7540 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7541 indices_section = cSecDof > 0 ? cSec : section; 7542 if (numFields) { 7543 PetscInt fStart[32], fEnd[32]; 7544 7545 fStart[0] = 0; 7546 fEnd[0] = 0; 7547 for (PetscInt f = 0; f < numFields; f++) { 7548 PetscInt fDof = 0; 7549 7550 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7551 fStart[f + 1] = fStart[f] + fDof; 7552 fEnd[f + 1] = fStart[f + 1]; 7553 } 7554 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7555 // only apply permutations on one side 7556 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7557 for (PetscInt f = 0; f < numFields; f++) { 7558 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7559 } 7560 } else { 7561 PetscInt bEnd = 0; 7562 7563 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7564 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7565 7566 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7567 } 7568 } 7569 PetscFunctionReturn(PETSC_SUCCESS); 7570 } 7571 7572 PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[]) 7573 { 7574 Mat cMat; 7575 PetscSection aSec, cSec; 7576 IS aIS; 7577 PetscInt aStart = -1, aEnd = -1; 7578 PetscInt sStart = -1, sEnd = -1; 7579 PetscInt cStart = -1, cEnd = -1; 7580 const PetscInt *anchors; 7581 PetscInt numFields, p; 7582 PetscInt newNumPoints = 0, newNumIndices = 0; 7583 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7584 PetscInt oldOffsets[32]; 7585 PetscInt newOffsets[32]; 7586 PetscInt oldOffsetsCopy[32]; 7587 PetscInt newOffsetsCopy[32]; 7588 PetscScalar *modMat = NULL; 7589 PetscBool anyConstrained = PETSC_FALSE; 7590 7591 PetscFunctionBegin; 7592 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7593 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7594 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7595 7596 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7597 /* if there are point-to-point constraints */ 7598 if (aSec) { 7599 PetscCall(PetscArrayzero(newOffsets, 32)); 7600 PetscCall(PetscArrayzero(oldOffsets, 32)); 7601 PetscCall(ISGetIndices(aIS, &anchors)); 7602 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7603 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7604 /* figure out how many points are going to be in the new element matrix 7605 * (we allow double counting, because it's all just going to be summed 7606 * into the global matrix anyway) */ 7607 for (p = 0; p < 2 * numPoints; p += 2) { 7608 PetscInt b = points[p]; 7609 PetscInt bDof = 0, bSecDof = 0; 7610 7611 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7612 if (!bSecDof) continue; 7613 7614 for (PetscInt f = 0; f < numFields; f++) { 7615 PetscInt fDof = 0; 7616 7617 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7618 oldOffsets[f + 1] += fDof; 7619 } 7620 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7621 if (bDof) { 7622 /* this point is constrained */ 7623 /* it is going to be replaced by its anchors */ 7624 PetscInt bOff, q; 7625 7626 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7627 for (q = 0; q < bDof; q++) { 7628 PetscInt a = anchors[bOff + q]; 7629 PetscInt aDof = 0; 7630 7631 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7632 if (aDof) { 7633 anyConstrained = PETSC_TRUE; 7634 newNumPoints += 1; 7635 } 7636 newNumIndices += aDof; 7637 for (PetscInt f = 0; f < numFields; ++f) { 7638 PetscInt fDof = 0; 7639 7640 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7641 newOffsets[f + 1] += fDof; 7642 } 7643 } 7644 } else { 7645 /* this point is not constrained */ 7646 newNumPoints++; 7647 newNumIndices += bSecDof; 7648 for (PetscInt f = 0; f < numFields; ++f) { 7649 PetscInt fDof; 7650 7651 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7652 newOffsets[f + 1] += fDof; 7653 } 7654 } 7655 } 7656 } 7657 if (!anyConstrained) { 7658 if (outNumPoints) *outNumPoints = 0; 7659 if (outNumIndices) *outNumIndices = 0; 7660 if (outPoints) *outPoints = NULL; 7661 if (outMat) *outMat = NULL; 7662 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7663 PetscFunctionReturn(PETSC_SUCCESS); 7664 } 7665 7666 if (outNumPoints) *outNumPoints = newNumPoints; 7667 if (outNumIndices) *outNumIndices = newNumIndices; 7668 7669 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7670 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7671 7672 if (!outPoints && !outMat) { 7673 if (offsets) { 7674 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7675 } 7676 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7677 PetscFunctionReturn(PETSC_SUCCESS); 7678 } 7679 7680 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7681 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7682 7683 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7684 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7685 7686 /* output arrays */ 7687 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7688 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7689 7690 // get the new Points 7691 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7692 PetscInt b = points[2 * p]; 7693 PetscInt bDof = 0, bSecDof = 0, bOff; 7694 7695 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7696 if (!bSecDof) continue; 7697 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7698 if (bDof) { 7699 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7700 for (PetscInt q = 0; q < bDof; q++) { 7701 PetscInt a = anchors[bOff + q], aDof = 0; 7702 7703 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7704 if (aDof) { 7705 newPoints[2 * newP] = a; 7706 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7707 newP++; 7708 } 7709 } 7710 } else { 7711 newPoints[2 * newP] = b; 7712 newPoints[2 * newP + 1] = points[2 * p + 1]; 7713 newP++; 7714 } 7715 } 7716 7717 if (outMat) { 7718 PetscScalar *tmpMat; 7719 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7720 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7721 7722 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7723 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7724 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7725 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7726 7727 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7728 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7729 7730 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7731 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7732 7733 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7734 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7735 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7736 // for each field, insert the anchor modification into modMat 7737 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7738 PetscInt fStart = oldOffsets[f]; 7739 PetscInt fNewStart = newOffsets[f]; 7740 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7741 PetscInt b = points[2 * p]; 7742 PetscInt bDof = 0, bSecDof = 0, bOff; 7743 7744 if (b >= sStart && b < sEnd) { 7745 if (numFields) { 7746 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7747 } else { 7748 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7749 } 7750 } 7751 if (!bSecDof) continue; 7752 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7753 if (bDof) { 7754 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7755 for (PetscInt q = 0; q < bDof; q++, newP++) { 7756 PetscInt a = anchors[bOff + q], aDof = 0; 7757 7758 if (a >= sStart && a < sEnd) { 7759 if (numFields) { 7760 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7761 } else { 7762 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7763 } 7764 } 7765 if (aDof) { 7766 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7767 for (PetscInt d = 0; d < bSecDof; d++) { 7768 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7769 } 7770 } 7771 oNew += aDof; 7772 } 7773 } else { 7774 // Insert the identity matrix in this block 7775 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7776 oNew += bSecDof; 7777 newP++; 7778 } 7779 o += bSecDof; 7780 } 7781 } 7782 7783 *outMat = modMat; 7784 7785 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7786 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7787 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7788 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7789 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7790 } 7791 PetscCall(ISRestoreIndices(aIS, &anchors)); 7792 7793 /* output */ 7794 if (outPoints) { 7795 *outPoints = newPoints; 7796 } else { 7797 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7798 } 7799 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7800 PetscFunctionReturn(PETSC_SUCCESS); 7801 } 7802 7803 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat_Internal(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt numRows, PetscInt numCols, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyRight, PetscBool multiplyLeft) 7804 { 7805 PetscScalar *modMat = NULL; 7806 PetscInt newNumIndices = -1; 7807 7808 PetscFunctionBegin; 7809 /* If M is the matrix represented by values, get the matrix C such that we will add M * C (or, if multiplyLeft, C^T * M * C) into the global matrix. 7810 modMat is that matrix C */ 7811 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7812 if (outNumIndices) *outNumIndices = newNumIndices; 7813 if (modMat) { 7814 const PetscScalar *newValues = values; 7815 7816 if (multiplyRight) { 7817 PetscScalar *newNewValues = NULL; 7818 PetscBLASInt M = newNumIndices; 7819 PetscBLASInt N = numRows; 7820 PetscBLASInt K = numIndices; 7821 PetscScalar a = 1.0, b = 0.0; 7822 7823 PetscCheck(numCols == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of columns: %" PetscInt_FMT ", expected %" PetscInt_FMT, numCols, numIndices); 7824 7825 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7826 // row-major to column-major conversion, right multiplication becomes left multiplication 7827 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7828 7829 numCols = newNumIndices; 7830 newValues = newNewValues; 7831 } 7832 7833 if (multiplyLeft) { 7834 PetscScalar *newNewValues = NULL; 7835 PetscBLASInt M = numCols; 7836 PetscBLASInt N = newNumIndices; 7837 PetscBLASInt K = numIndices; 7838 PetscScalar a = 1.0, b = 0.0; 7839 7840 PetscCheck(numRows == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of rows: %" PetscInt_FMT ", expected %" PetscInt_FMT, numRows, numIndices); 7841 7842 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7843 // row-major to column-major conversion, left multiplication becomes right multiplication 7844 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7845 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7846 newValues = newNewValues; 7847 } 7848 *outValues = (PetscScalar *)newValues; 7849 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7850 } 7851 PetscFunctionReturn(PETSC_SUCCESS); 7852 } 7853 7854 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft) 7855 { 7856 PetscFunctionBegin; 7857 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7858 PetscFunctionReturn(PETSC_SUCCESS); 7859 } 7860 7861 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7862 { 7863 /* Closure ordering */ 7864 PetscSection clSection; 7865 IS clPoints; 7866 const PetscInt *clp; 7867 PetscInt *points; 7868 PetscInt Ncl, Ni = 0; 7869 7870 PetscFunctionBeginHot; 7871 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7872 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7873 PetscInt dof; 7874 7875 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7876 Ni += dof; 7877 } 7878 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7879 *closureSize = Ni; 7880 PetscFunctionReturn(PETSC_SUCCESS); 7881 } 7882 7883 static PetscErrorCode DMPlexGetClosureIndices_Internal(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numRows, PetscInt *numCols, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[], PetscBool multiplyRight, PetscBool multiplyLeft) 7884 { 7885 /* Closure ordering */ 7886 PetscSection clSection; 7887 IS clPoints; 7888 const PetscInt *clp; 7889 PetscInt *points; 7890 const PetscInt *clperm = NULL; 7891 /* Dof permutation and sign flips */ 7892 const PetscInt **perms[32] = {NULL}; 7893 const PetscScalar **flips[32] = {NULL}; 7894 PetscScalar *valCopy = NULL; 7895 /* Hanging node constraints */ 7896 PetscInt *pointsC = NULL; 7897 PetscScalar *valuesC = NULL; 7898 PetscInt NclC, NiC; 7899 7900 PetscInt *idx; 7901 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7902 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7903 PetscInt idxStart, idxEnd; 7904 PetscInt nRows, nCols; 7905 7906 PetscFunctionBeginHot; 7907 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7908 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7909 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7910 PetscAssertPointer(numRows, 6); 7911 PetscAssertPointer(numCols, 7); 7912 if (indices) PetscAssertPointer(indices, 8); 7913 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7914 if (values) PetscAssertPointer(values, 10); 7915 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7916 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7917 PetscCall(PetscArrayzero(offsets, 32)); 7918 /* 1) Get points in closure */ 7919 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7920 if (useClPerm) { 7921 PetscInt depth, clsize; 7922 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7923 for (clsize = 0, p = 0; p < Ncl; p++) { 7924 PetscInt dof; 7925 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7926 clsize += dof; 7927 } 7928 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7929 } 7930 /* 2) Get number of indices on these points and field offsets from section */ 7931 for (p = 0; p < Ncl * 2; p += 2) { 7932 PetscInt dof, fdof; 7933 7934 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7935 for (f = 0; f < Nf; ++f) { 7936 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7937 offsets[f + 1] += fdof; 7938 } 7939 Ni += dof; 7940 } 7941 if (*numRows == -1) *numRows = Ni; 7942 if (*numCols == -1) *numCols = Ni; 7943 nRows = *numRows; 7944 nCols = *numCols; 7945 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7946 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7947 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7948 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7949 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7950 for (f = 0; f < PetscMax(1, Nf); ++f) { 7951 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7952 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7953 /* may need to apply sign changes to the element matrix */ 7954 if (values && flips[f]) { 7955 PetscInt foffset = offsets[f]; 7956 7957 for (p = 0; p < Ncl; ++p) { 7958 PetscInt pnt = points[2 * p], fdof; 7959 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7960 7961 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7962 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7963 if (flip) { 7964 PetscInt i, j, k; 7965 7966 if (!valCopy) { 7967 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7968 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7969 *values = valCopy; 7970 } 7971 for (i = 0; i < fdof; ++i) { 7972 PetscScalar fval = flip[i]; 7973 7974 if (multiplyRight) { 7975 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7976 } 7977 if (multiplyLeft) { 7978 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7979 } 7980 } 7981 } 7982 foffset += fdof; 7983 } 7984 } 7985 } 7986 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7987 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7988 if (NclC) { 7989 if (multiplyRight) { *numCols = nCols = NiC; } 7990 if (multiplyLeft) { *numRows = nRows = NiC; } 7991 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7992 for (f = 0; f < PetscMax(1, Nf); ++f) { 7993 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7994 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7995 } 7996 for (f = 0; f < PetscMax(1, Nf); ++f) { 7997 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7998 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7999 } 8000 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8001 Ncl = NclC; 8002 Ni = NiC; 8003 points = pointsC; 8004 if (values) *values = valuesC; 8005 } 8006 /* 5) Calculate indices */ 8007 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8008 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8009 if (Nf) { 8010 PetscInt idxOff; 8011 PetscBool useFieldOffsets; 8012 8013 if (outOffsets) { 8014 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8015 } 8016 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8017 if (useFieldOffsets) { 8018 for (p = 0; p < Ncl; ++p) { 8019 const PetscInt pnt = points[p * 2]; 8020 8021 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8022 } 8023 } else { 8024 for (p = 0; p < Ncl; ++p) { 8025 const PetscInt pnt = points[p * 2]; 8026 8027 if (pnt < idxStart || pnt >= idxEnd) continue; 8028 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8029 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8030 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8031 * global section. */ 8032 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8033 } 8034 } 8035 } else { 8036 PetscInt off = 0, idxOff; 8037 8038 for (p = 0; p < Ncl; ++p) { 8039 const PetscInt pnt = points[p * 2]; 8040 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8041 8042 if (pnt < idxStart || pnt >= idxEnd) continue; 8043 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8044 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8045 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8046 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8047 } 8048 } 8049 /* 6) Cleanup */ 8050 for (f = 0; f < PetscMax(1, Nf); ++f) { 8051 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8052 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8053 } 8054 if (NclC) { 8055 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8056 } else { 8057 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8058 } 8059 8060 if (indices) *indices = idx; 8061 PetscFunctionReturn(PETSC_SUCCESS); 8062 } 8063 8064 /*@C 8065 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8066 8067 Not collective 8068 8069 Input Parameters: 8070 + dm - The `DM` 8071 . section - The `PetscSection` describing the points (a local section) 8072 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8073 . point - The point defining the closure 8074 - useClPerm - Use the closure point permutation if available 8075 8076 Output Parameters: 8077 + numIndices - The number of dof indices in the closure of point with the input sections 8078 . indices - The dof indices 8079 . outOffsets - Array to write the field offsets into, or `NULL` 8080 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8081 8082 Level: advanced 8083 8084 Notes: 8085 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 8086 8087 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8088 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8089 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8090 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8091 indices (with the above semantics) are implied. 8092 8093 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8094 `PetscSection`, `DMGetGlobalSection()` 8095 @*/ 8096 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8097 { 8098 PetscInt numRows = -1, numCols = -1; 8099 8100 PetscFunctionBeginHot; 8101 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8102 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8103 *numIndices = numRows; 8104 PetscFunctionReturn(PETSC_SUCCESS); 8105 } 8106 8107 /*@C 8108 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8109 8110 Not collective 8111 8112 Input Parameters: 8113 + dm - The `DM` 8114 . section - The `PetscSection` describing the points (a local section) 8115 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8116 . point - The point defining the closure 8117 - useClPerm - Use the closure point permutation if available 8118 8119 Output Parameters: 8120 + numIndices - The number of dof indices in the closure of point with the input sections 8121 . indices - The dof indices 8122 . outOffsets - Array to write the field offsets into, or `NULL` 8123 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8124 8125 Level: advanced 8126 8127 Notes: 8128 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8129 8130 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8131 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8132 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8133 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8134 indices (with the above semantics) are implied. 8135 8136 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8137 @*/ 8138 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8139 { 8140 PetscFunctionBegin; 8141 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8142 PetscAssertPointer(indices, 7); 8143 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8144 PetscFunctionReturn(PETSC_SUCCESS); 8145 } 8146 8147 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8148 { 8149 DM_Plex *mesh = (DM_Plex *)dm->data; 8150 PetscInt *indices; 8151 PetscInt numIndices; 8152 const PetscScalar *valuesOrig = values; 8153 PetscErrorCode ierr; 8154 8155 PetscFunctionBegin; 8156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8157 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8158 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8159 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8160 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8161 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8162 8163 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8164 8165 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8166 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8167 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8168 if (ierr) { 8169 PetscMPIInt rank; 8170 8171 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8172 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8173 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8174 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8175 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8176 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8177 } 8178 if (mesh->printFEM > 1) { 8179 PetscInt i; 8180 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8181 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8182 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8183 } 8184 8185 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8186 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8187 PetscFunctionReturn(PETSC_SUCCESS); 8188 } 8189 8190 /*@C 8191 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8192 8193 Not collective 8194 8195 Input Parameters: 8196 + dm - The `DM` 8197 . section - The section describing the layout in `v`, or `NULL` to use the default section 8198 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8199 . A - The matrix 8200 . point - The point in the `DM` 8201 . values - The array of values 8202 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8203 8204 Level: intermediate 8205 8206 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8207 @*/ 8208 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8209 { 8210 PetscFunctionBegin; 8211 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8212 PetscFunctionReturn(PETSC_SUCCESS); 8213 } 8214 8215 /*@C 8216 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8217 8218 Not collective 8219 8220 Input Parameters: 8221 + dmRow - The `DM` for the row fields 8222 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8223 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8224 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8225 . dmCol - The `DM` for the column fields 8226 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8227 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8228 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8229 . A - The matrix 8230 . point - The point in the `DM` 8231 . values - The array of values 8232 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8233 8234 Level: intermediate 8235 8236 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8237 @*/ 8238 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) 8239 { 8240 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8241 PetscInt *indicesRow, *indicesCol; 8242 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8243 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8244 8245 PetscErrorCode ierr; 8246 8247 PetscFunctionBegin; 8248 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8249 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8250 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8251 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8252 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8253 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8254 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8255 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8256 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8257 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8258 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8259 8260 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8261 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8262 valuesV1 = valuesV0; 8263 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8264 valuesV2 = valuesV1; 8265 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8266 8267 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8268 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8269 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8270 if (ierr) { 8271 PetscMPIInt rank; 8272 8273 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8274 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8275 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8276 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8277 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8278 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8279 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8280 } 8281 8282 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8283 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8284 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8285 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8286 PetscFunctionReturn(PETSC_SUCCESS); 8287 } 8288 8289 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8290 { 8291 DM_Plex *mesh = (DM_Plex *)dmf->data; 8292 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8293 PetscInt *cpoints = NULL; 8294 PetscInt *findices, *cindices; 8295 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8296 PetscInt foffsets[32], coffsets[32]; 8297 DMPolytopeType ct; 8298 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8299 PetscErrorCode ierr; 8300 8301 PetscFunctionBegin; 8302 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8303 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8304 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8305 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8306 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8307 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8308 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8309 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8310 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8311 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8312 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8313 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8314 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8315 PetscCall(PetscArrayzero(foffsets, 32)); 8316 PetscCall(PetscArrayzero(coffsets, 32)); 8317 /* Column indices */ 8318 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8319 maxFPoints = numCPoints; 8320 /* Compress out points not in the section */ 8321 /* TODO: Squeeze out points with 0 dof as well */ 8322 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8323 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8324 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8325 cpoints[q * 2] = cpoints[p]; 8326 cpoints[q * 2 + 1] = cpoints[p + 1]; 8327 ++q; 8328 } 8329 } 8330 numCPoints = q; 8331 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8332 PetscInt fdof; 8333 8334 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8335 if (!dof) continue; 8336 for (f = 0; f < numFields; ++f) { 8337 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8338 coffsets[f + 1] += fdof; 8339 } 8340 numCIndices += dof; 8341 } 8342 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8343 /* Row indices */ 8344 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8345 { 8346 DMPlexTransform tr; 8347 DMPolytopeType *rct; 8348 PetscInt *rsize, *rcone, *rornt, Nt; 8349 8350 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8351 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8352 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8353 numSubcells = rsize[Nt - 1]; 8354 PetscCall(DMPlexTransformDestroy(&tr)); 8355 } 8356 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8357 for (r = 0, q = 0; r < numSubcells; ++r) { 8358 /* TODO Map from coarse to fine cells */ 8359 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8360 /* Compress out points not in the section */ 8361 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8362 for (p = 0; p < numFPoints * 2; p += 2) { 8363 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8364 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8365 if (!dof) continue; 8366 for (s = 0; s < q; ++s) 8367 if (fpoints[p] == ftotpoints[s * 2]) break; 8368 if (s < q) continue; 8369 ftotpoints[q * 2] = fpoints[p]; 8370 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8371 ++q; 8372 } 8373 } 8374 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8375 } 8376 numFPoints = q; 8377 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8378 PetscInt fdof; 8379 8380 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8381 if (!dof) continue; 8382 for (f = 0; f < numFields; ++f) { 8383 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8384 foffsets[f + 1] += fdof; 8385 } 8386 numFIndices += dof; 8387 } 8388 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8389 8390 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8391 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8392 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8393 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8394 if (numFields) { 8395 const PetscInt **permsF[32] = {NULL}; 8396 const PetscInt **permsC[32] = {NULL}; 8397 8398 for (f = 0; f < numFields; f++) { 8399 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8400 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8401 } 8402 for (p = 0; p < numFPoints; p++) { 8403 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8404 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8405 } 8406 for (p = 0; p < numCPoints; p++) { 8407 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8408 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8409 } 8410 for (f = 0; f < numFields; f++) { 8411 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8412 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8413 } 8414 } else { 8415 const PetscInt **permsF = NULL; 8416 const PetscInt **permsC = NULL; 8417 8418 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8419 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8420 for (p = 0, off = 0; p < numFPoints; p++) { 8421 const PetscInt *perm = permsF ? permsF[p] : NULL; 8422 8423 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8424 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8425 } 8426 for (p = 0, off = 0; p < numCPoints; p++) { 8427 const PetscInt *perm = permsC ? permsC[p] : NULL; 8428 8429 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8430 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8431 } 8432 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8433 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8434 } 8435 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8436 /* TODO: flips */ 8437 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8438 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8439 if (ierr) { 8440 PetscMPIInt rank; 8441 8442 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8443 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8444 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8445 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8446 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8447 } 8448 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8449 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8450 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8451 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8452 PetscFunctionReturn(PETSC_SUCCESS); 8453 } 8454 8455 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8456 { 8457 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8458 PetscInt *cpoints = NULL; 8459 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8460 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8461 DMPolytopeType ct; 8462 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8463 8464 PetscFunctionBegin; 8465 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8466 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8467 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8468 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8469 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8470 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8471 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8472 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8473 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8474 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8475 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8476 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8477 /* Column indices */ 8478 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8479 maxFPoints = numCPoints; 8480 /* Compress out points not in the section */ 8481 /* TODO: Squeeze out points with 0 dof as well */ 8482 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8483 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8484 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8485 cpoints[q * 2] = cpoints[p]; 8486 cpoints[q * 2 + 1] = cpoints[p + 1]; 8487 ++q; 8488 } 8489 } 8490 numCPoints = q; 8491 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8492 PetscInt fdof; 8493 8494 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8495 if (!dof) continue; 8496 for (f = 0; f < numFields; ++f) { 8497 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8498 coffsets[f + 1] += fdof; 8499 } 8500 numCIndices += dof; 8501 } 8502 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8503 /* Row indices */ 8504 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8505 { 8506 DMPlexTransform tr; 8507 DMPolytopeType *rct; 8508 PetscInt *rsize, *rcone, *rornt, Nt; 8509 8510 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8511 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8512 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8513 numSubcells = rsize[Nt - 1]; 8514 PetscCall(DMPlexTransformDestroy(&tr)); 8515 } 8516 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8517 for (r = 0, q = 0; r < numSubcells; ++r) { 8518 /* TODO Map from coarse to fine cells */ 8519 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8520 /* Compress out points not in the section */ 8521 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8522 for (p = 0; p < numFPoints * 2; p += 2) { 8523 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8524 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8525 if (!dof) continue; 8526 for (s = 0; s < q; ++s) 8527 if (fpoints[p] == ftotpoints[s * 2]) break; 8528 if (s < q) continue; 8529 ftotpoints[q * 2] = fpoints[p]; 8530 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8531 ++q; 8532 } 8533 } 8534 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8535 } 8536 numFPoints = q; 8537 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8538 PetscInt fdof; 8539 8540 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8541 if (!dof) continue; 8542 for (f = 0; f < numFields; ++f) { 8543 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8544 foffsets[f + 1] += fdof; 8545 } 8546 numFIndices += dof; 8547 } 8548 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8549 8550 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8551 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8552 if (numFields) { 8553 const PetscInt **permsF[32] = {NULL}; 8554 const PetscInt **permsC[32] = {NULL}; 8555 8556 for (f = 0; f < numFields; f++) { 8557 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8558 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8559 } 8560 for (p = 0; p < numFPoints; p++) { 8561 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8562 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8563 } 8564 for (p = 0; p < numCPoints; p++) { 8565 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8566 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8567 } 8568 for (f = 0; f < numFields; f++) { 8569 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8570 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8571 } 8572 } else { 8573 const PetscInt **permsF = NULL; 8574 const PetscInt **permsC = NULL; 8575 8576 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8577 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8578 for (p = 0, off = 0; p < numFPoints; p++) { 8579 const PetscInt *perm = permsF ? permsF[p] : NULL; 8580 8581 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8582 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8583 } 8584 for (p = 0, off = 0; p < numCPoints; p++) { 8585 const PetscInt *perm = permsC ? permsC[p] : NULL; 8586 8587 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8588 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8589 } 8590 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8591 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8592 } 8593 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8594 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8595 PetscFunctionReturn(PETSC_SUCCESS); 8596 } 8597 8598 /*@ 8599 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8600 8601 Input Parameter: 8602 . dm - The `DMPLEX` object 8603 8604 Output Parameter: 8605 . cellHeight - The height of a cell 8606 8607 Level: developer 8608 8609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8610 @*/ 8611 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8612 { 8613 DM_Plex *mesh = (DM_Plex *)dm->data; 8614 8615 PetscFunctionBegin; 8616 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8617 PetscAssertPointer(cellHeight, 2); 8618 *cellHeight = mesh->vtkCellHeight; 8619 PetscFunctionReturn(PETSC_SUCCESS); 8620 } 8621 8622 /*@ 8623 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8624 8625 Input Parameters: 8626 + dm - The `DMPLEX` object 8627 - cellHeight - The height of a cell 8628 8629 Level: developer 8630 8631 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8632 @*/ 8633 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8634 { 8635 DM_Plex *mesh = (DM_Plex *)dm->data; 8636 8637 PetscFunctionBegin; 8638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8639 mesh->vtkCellHeight = cellHeight; 8640 PetscFunctionReturn(PETSC_SUCCESS); 8641 } 8642 8643 /*@ 8644 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8645 8646 Input Parameters: 8647 + dm - The `DMPLEX` object 8648 - ct - The `DMPolytopeType` of the cell 8649 8650 Output Parameters: 8651 + start - The first cell of this type, or `NULL` 8652 - end - The upper bound on this celltype, or `NULL` 8653 8654 Level: advanced 8655 8656 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8657 @*/ 8658 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8659 { 8660 DM_Plex *mesh = (DM_Plex *)dm->data; 8661 DMLabel label; 8662 PetscInt pStart, pEnd; 8663 8664 PetscFunctionBegin; 8665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8666 if (start) { 8667 PetscAssertPointer(start, 3); 8668 *start = 0; 8669 } 8670 if (end) { 8671 PetscAssertPointer(end, 4); 8672 *end = 0; 8673 } 8674 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8675 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8676 if (mesh->tr) { 8677 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8678 } else { 8679 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8680 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8681 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8682 } 8683 PetscFunctionReturn(PETSC_SUCCESS); 8684 } 8685 8686 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8687 { 8688 PetscSection section, globalSection; 8689 PetscInt *numbers, p; 8690 8691 PetscFunctionBegin; 8692 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8693 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8694 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8695 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8696 PetscCall(PetscSectionSetUp(section)); 8697 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8698 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8699 for (p = pStart; p < pEnd; ++p) { 8700 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8701 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8702 else numbers[p - pStart] += shift; 8703 } 8704 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8705 if (globalSize) { 8706 PetscLayout layout; 8707 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8708 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8709 PetscCall(PetscLayoutDestroy(&layout)); 8710 } 8711 PetscCall(PetscSectionDestroy(§ion)); 8712 PetscCall(PetscSectionDestroy(&globalSection)); 8713 PetscFunctionReturn(PETSC_SUCCESS); 8714 } 8715 8716 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8717 { 8718 PetscInt cellHeight, cStart, cEnd; 8719 8720 PetscFunctionBegin; 8721 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8722 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8723 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8724 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8725 PetscFunctionReturn(PETSC_SUCCESS); 8726 } 8727 8728 /*@ 8729 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8730 8731 Input Parameter: 8732 . dm - The `DMPLEX` object 8733 8734 Output Parameter: 8735 . globalCellNumbers - Global cell numbers for all cells on this process 8736 8737 Level: developer 8738 8739 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8740 @*/ 8741 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8742 { 8743 DM_Plex *mesh = (DM_Plex *)dm->data; 8744 8745 PetscFunctionBegin; 8746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8747 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8748 *globalCellNumbers = mesh->globalCellNumbers; 8749 PetscFunctionReturn(PETSC_SUCCESS); 8750 } 8751 8752 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8753 { 8754 PetscInt vStart, vEnd; 8755 8756 PetscFunctionBegin; 8757 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8758 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8759 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8760 PetscFunctionReturn(PETSC_SUCCESS); 8761 } 8762 8763 /*@ 8764 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8765 8766 Input Parameter: 8767 . dm - The `DMPLEX` object 8768 8769 Output Parameter: 8770 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8771 8772 Level: developer 8773 8774 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8775 @*/ 8776 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8777 { 8778 DM_Plex *mesh = (DM_Plex *)dm->data; 8779 8780 PetscFunctionBegin; 8781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8782 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8783 *globalVertexNumbers = mesh->globalVertexNumbers; 8784 PetscFunctionReturn(PETSC_SUCCESS); 8785 } 8786 8787 /*@ 8788 DMPlexCreatePointNumbering - Create a global numbering for all points. 8789 8790 Collective 8791 8792 Input Parameter: 8793 . dm - The `DMPLEX` object 8794 8795 Output Parameter: 8796 . globalPointNumbers - Global numbers for all points on this process 8797 8798 Level: developer 8799 8800 Notes: 8801 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8802 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8803 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8804 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8805 8806 The partitioned mesh is 8807 ``` 8808 (2)--0--(3)--1--(4) (1)--0--(2) 8809 ``` 8810 and its global numbering is 8811 ``` 8812 (3)--0--(4)--1--(5)--2--(6) 8813 ``` 8814 Then the global numbering is provided as 8815 ``` 8816 [0] Number of indices in set 5 8817 [0] 0 0 8818 [0] 1 1 8819 [0] 2 3 8820 [0] 3 4 8821 [0] 4 -6 8822 [1] Number of indices in set 3 8823 [1] 0 2 8824 [1] 1 5 8825 [1] 2 6 8826 ``` 8827 8828 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8829 @*/ 8830 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8831 { 8832 IS nums[4]; 8833 PetscInt depths[4], gdepths[4], starts[4]; 8834 PetscInt depth, d, shift = 0; 8835 PetscBool empty = PETSC_FALSE; 8836 8837 PetscFunctionBegin; 8838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8839 PetscCall(DMPlexGetDepth(dm, &depth)); 8840 // For unstratified meshes use dim instead of depth 8841 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8842 // If any stratum is empty, we must mark all empty 8843 for (d = 0; d <= depth; ++d) { 8844 PetscInt end; 8845 8846 depths[d] = depth - d; 8847 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8848 if (!(starts[d] - end)) empty = PETSC_TRUE; 8849 } 8850 if (empty) 8851 for (d = 0; d <= depth; ++d) { 8852 depths[d] = -1; 8853 starts[d] = -1; 8854 } 8855 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8856 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8857 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]); 8858 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8859 for (d = 0; d <= depth; ++d) { 8860 PetscInt pStart, pEnd, gsize; 8861 8862 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8863 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8864 shift += gsize; 8865 } 8866 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8867 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8868 PetscFunctionReturn(PETSC_SUCCESS); 8869 } 8870 8871 /*@ 8872 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8873 8874 Collective 8875 8876 Input Parameter: 8877 . dm - The `DMPLEX` object 8878 8879 Output Parameter: 8880 . globalEdgeNumbers - Global numbers for all edges on this process 8881 8882 Level: developer 8883 8884 Notes: 8885 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). In the IS, owned edges will have their non-negative value while edges owned by different ranks will be involuted -(idx+1). 8886 8887 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8888 @*/ 8889 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8890 { 8891 PetscSF sf; 8892 PetscInt eStart, eEnd; 8893 8894 PetscFunctionBegin; 8895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8896 PetscCall(DMGetPointSF(dm, &sf)); 8897 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8898 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8899 PetscFunctionReturn(PETSC_SUCCESS); 8900 } 8901 8902 /*@ 8903 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8904 8905 Input Parameter: 8906 . dm - The `DMPLEX` object 8907 8908 Output Parameter: 8909 . ranks - The rank field 8910 8911 Options Database Key: 8912 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8913 8914 Level: intermediate 8915 8916 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8917 @*/ 8918 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8919 { 8920 DM rdm; 8921 PetscFE fe; 8922 PetscScalar *r; 8923 PetscMPIInt rank; 8924 DMPolytopeType ct; 8925 PetscInt dim, cStart, cEnd, c; 8926 PetscBool simplex; 8927 8928 PetscFunctionBeginUser; 8929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8930 PetscAssertPointer(ranks, 2); 8931 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8932 PetscCall(DMClone(dm, &rdm)); 8933 PetscCall(DMGetDimension(rdm, &dim)); 8934 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8935 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8936 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8937 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8938 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8939 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8940 PetscCall(PetscFEDestroy(&fe)); 8941 PetscCall(DMCreateDS(rdm)); 8942 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8943 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8944 PetscCall(VecGetArray(*ranks, &r)); 8945 for (c = cStart; c < cEnd; ++c) { 8946 PetscScalar *lr; 8947 8948 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8949 if (lr) *lr = rank; 8950 } 8951 PetscCall(VecRestoreArray(*ranks, &r)); 8952 PetscCall(DMDestroy(&rdm)); 8953 PetscFunctionReturn(PETSC_SUCCESS); 8954 } 8955 8956 /*@ 8957 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8958 8959 Input Parameters: 8960 + dm - The `DMPLEX` 8961 - label - The `DMLabel` 8962 8963 Output Parameter: 8964 . val - The label value field 8965 8966 Options Database Key: 8967 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8968 8969 Level: intermediate 8970 8971 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8972 @*/ 8973 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8974 { 8975 DM rdm, plex; 8976 Vec lval; 8977 PetscSection section; 8978 PetscFE fe; 8979 PetscScalar *v; 8980 PetscInt dim, pStart, pEnd, p, cStart; 8981 DMPolytopeType ct; 8982 char name[PETSC_MAX_PATH_LEN]; 8983 const char *lname, *prefix; 8984 8985 PetscFunctionBeginUser; 8986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8987 PetscAssertPointer(label, 2); 8988 PetscAssertPointer(val, 3); 8989 PetscCall(DMClone(dm, &rdm)); 8990 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8991 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8992 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8993 PetscCall(DMDestroy(&plex)); 8994 PetscCall(DMGetDimension(rdm, &dim)); 8995 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8996 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8997 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8998 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8999 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9000 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9001 PetscCall(PetscFEDestroy(&fe)); 9002 PetscCall(DMCreateDS(rdm)); 9003 PetscCall(DMCreateGlobalVector(rdm, val)); 9004 PetscCall(DMCreateLocalVector(rdm, &lval)); 9005 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9006 PetscCall(DMGetLocalSection(rdm, §ion)); 9007 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9008 PetscCall(VecGetArray(lval, &v)); 9009 for (p = pStart; p < pEnd; ++p) { 9010 PetscInt cval, dof, off; 9011 9012 PetscCall(PetscSectionGetDof(section, p, &dof)); 9013 if (!dof) continue; 9014 PetscCall(DMLabelGetValue(label, p, &cval)); 9015 PetscCall(PetscSectionGetOffset(section, p, &off)); 9016 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9017 } 9018 PetscCall(VecRestoreArray(lval, &v)); 9019 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9020 PetscCall(VecDestroy(&lval)); 9021 PetscCall(DMDestroy(&rdm)); 9022 PetscFunctionReturn(PETSC_SUCCESS); 9023 } 9024 9025 /*@ 9026 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9027 9028 Input Parameter: 9029 . dm - The `DMPLEX` object 9030 9031 Level: developer 9032 9033 Notes: 9034 This is a useful diagnostic when creating meshes programmatically. 9035 9036 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9037 9038 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9039 @*/ 9040 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9041 { 9042 PetscSection coneSection, supportSection; 9043 const PetscInt *cone, *support; 9044 PetscInt coneSize, c, supportSize, s; 9045 PetscInt pStart, pEnd, p, pp, csize, ssize; 9046 PetscBool storagecheck = PETSC_TRUE; 9047 9048 PetscFunctionBegin; 9049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9050 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9051 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9052 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9053 /* Check that point p is found in the support of its cone points, and vice versa */ 9054 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9055 for (p = pStart; p < pEnd; ++p) { 9056 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9057 PetscCall(DMPlexGetCone(dm, p, &cone)); 9058 for (c = 0; c < coneSize; ++c) { 9059 PetscBool dup = PETSC_FALSE; 9060 PetscInt d; 9061 for (d = c - 1; d >= 0; --d) { 9062 if (cone[c] == cone[d]) { 9063 dup = PETSC_TRUE; 9064 break; 9065 } 9066 } 9067 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9068 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9069 for (s = 0; s < supportSize; ++s) { 9070 if (support[s] == p) break; 9071 } 9072 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9073 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9074 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9075 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9076 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9077 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9078 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9079 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]); 9080 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9081 } 9082 } 9083 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9084 if (p != pp) { 9085 storagecheck = PETSC_FALSE; 9086 continue; 9087 } 9088 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9089 PetscCall(DMPlexGetSupport(dm, p, &support)); 9090 for (s = 0; s < supportSize; ++s) { 9091 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9092 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9093 for (c = 0; c < coneSize; ++c) { 9094 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9095 if (cone[c] != pp) { 9096 c = 0; 9097 break; 9098 } 9099 if (cone[c] == p) break; 9100 } 9101 if (c >= coneSize) { 9102 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9103 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9104 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9105 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9106 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9107 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9108 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9109 } 9110 } 9111 } 9112 if (storagecheck) { 9113 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9114 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9115 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9116 } 9117 PetscFunctionReturn(PETSC_SUCCESS); 9118 } 9119 9120 /* 9121 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. 9122 */ 9123 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9124 { 9125 DMPolytopeType cct; 9126 PetscInt ptpoints[4]; 9127 const PetscInt *cone, *ccone, *ptcone; 9128 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9129 9130 PetscFunctionBegin; 9131 *unsplit = 0; 9132 switch (ct) { 9133 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9134 ptpoints[npt++] = c; 9135 break; 9136 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9137 PetscCall(DMPlexGetCone(dm, c, &cone)); 9138 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9139 for (cp = 0; cp < coneSize; ++cp) { 9140 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9141 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9142 } 9143 break; 9144 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9145 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9146 PetscCall(DMPlexGetCone(dm, c, &cone)); 9147 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9148 for (cp = 0; cp < coneSize; ++cp) { 9149 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9150 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9151 for (ccp = 0; ccp < cconeSize; ++ccp) { 9152 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9153 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9154 PetscInt p; 9155 for (p = 0; p < npt; ++p) 9156 if (ptpoints[p] == ccone[ccp]) break; 9157 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9158 } 9159 } 9160 } 9161 break; 9162 default: 9163 break; 9164 } 9165 for (pt = 0; pt < npt; ++pt) { 9166 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9167 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9168 } 9169 PetscFunctionReturn(PETSC_SUCCESS); 9170 } 9171 9172 /*@ 9173 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9174 9175 Input Parameters: 9176 + dm - The `DMPLEX` object 9177 - cellHeight - Normally 0 9178 9179 Level: developer 9180 9181 Notes: 9182 This is a useful diagnostic when creating meshes programmatically. 9183 Currently applicable only to homogeneous simplex or tensor meshes. 9184 9185 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9186 9187 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9188 @*/ 9189 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9190 { 9191 DMPlexInterpolatedFlag interp; 9192 DMPolytopeType ct; 9193 PetscInt vStart, vEnd, cStart, cEnd, c; 9194 9195 PetscFunctionBegin; 9196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9197 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9198 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9199 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9200 for (c = cStart; c < cEnd; ++c) { 9201 PetscInt *closure = NULL; 9202 PetscInt coneSize, closureSize, cl, Nv = 0; 9203 9204 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9205 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9206 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9207 if (interp == DMPLEX_INTERPOLATED_FULL) { 9208 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9209 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)); 9210 } 9211 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9212 for (cl = 0; cl < closureSize * 2; cl += 2) { 9213 const PetscInt p = closure[cl]; 9214 if ((p >= vStart) && (p < vEnd)) ++Nv; 9215 } 9216 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9217 /* Special Case: Tensor faces with identified vertices */ 9218 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9219 PetscInt unsplit; 9220 9221 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9222 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9223 } 9224 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)); 9225 } 9226 PetscFunctionReturn(PETSC_SUCCESS); 9227 } 9228 9229 /*@ 9230 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9231 9232 Collective 9233 9234 Input Parameters: 9235 + dm - The `DMPLEX` object 9236 - cellHeight - Normally 0 9237 9238 Level: developer 9239 9240 Notes: 9241 This is a useful diagnostic when creating meshes programmatically. 9242 This routine is only relevant for meshes that are fully interpolated across all ranks. 9243 It will error out if a partially interpolated mesh is given on some rank. 9244 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9245 9246 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9247 9248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9249 @*/ 9250 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9251 { 9252 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9253 DMPlexInterpolatedFlag interpEnum; 9254 9255 PetscFunctionBegin; 9256 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9257 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9258 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9259 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9260 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9261 PetscFunctionReturn(PETSC_SUCCESS); 9262 } 9263 9264 PetscCall(DMGetDimension(dm, &dim)); 9265 PetscCall(DMPlexGetDepth(dm, &depth)); 9266 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9267 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9268 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9269 for (c = cStart; c < cEnd; ++c) { 9270 const PetscInt *cone, *ornt, *faceSizes, *faces; 9271 const DMPolytopeType *faceTypes; 9272 DMPolytopeType ct; 9273 PetscInt numFaces, coneSize, f; 9274 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9275 9276 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9277 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9278 if (unsplit) continue; 9279 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9280 PetscCall(DMPlexGetCone(dm, c, &cone)); 9281 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9282 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9283 for (cl = 0; cl < closureSize * 2; cl += 2) { 9284 const PetscInt p = closure[cl]; 9285 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9286 } 9287 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9288 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); 9289 for (f = 0; f < numFaces; ++f) { 9290 DMPolytopeType fct; 9291 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9292 9293 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9294 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9295 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9296 const PetscInt p = fclosure[cl]; 9297 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9298 } 9299 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]); 9300 for (v = 0; v < fnumCorners; ++v) { 9301 if (fclosure[v] != faces[fOff + v]) { 9302 PetscInt v1; 9303 9304 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9305 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9306 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9307 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9308 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9309 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]); 9310 } 9311 } 9312 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9313 fOff += faceSizes[f]; 9314 } 9315 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9316 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9317 } 9318 } 9319 PetscFunctionReturn(PETSC_SUCCESS); 9320 } 9321 9322 /*@ 9323 DMPlexCheckGeometry - Check the geometry of mesh cells 9324 9325 Input Parameter: 9326 . dm - The `DMPLEX` object 9327 9328 Level: developer 9329 9330 Notes: 9331 This is a useful diagnostic when creating meshes programmatically. 9332 9333 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9334 9335 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9336 @*/ 9337 PetscErrorCode DMPlexCheckGeometry(DM dm) 9338 { 9339 Vec coordinates; 9340 PetscReal detJ, J[9], refVol = 1.0; 9341 PetscReal vol; 9342 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9343 9344 PetscFunctionBegin; 9345 PetscCall(DMGetDimension(dm, &dim)); 9346 PetscCall(DMGetCoordinateDim(dm, &dE)); 9347 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9348 PetscCall(DMPlexGetDepth(dm, &depth)); 9349 for (d = 0; d < dim; ++d) refVol *= 2.0; 9350 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9351 /* Make sure local coordinates are created, because that step is collective */ 9352 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9353 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9354 for (c = cStart; c < cEnd; ++c) { 9355 DMPolytopeType ct; 9356 PetscInt unsplit; 9357 PetscBool ignoreZeroVol = PETSC_FALSE; 9358 9359 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9360 switch (ct) { 9361 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9362 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9363 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9364 ignoreZeroVol = PETSC_TRUE; 9365 break; 9366 default: 9367 break; 9368 } 9369 switch (ct) { 9370 case DM_POLYTOPE_TRI_PRISM: 9371 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9372 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9373 case DM_POLYTOPE_PYRAMID: 9374 continue; 9375 default: 9376 break; 9377 } 9378 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9379 if (unsplit) continue; 9380 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9381 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); 9382 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9383 /* This should work with periodicity since DG coordinates should be used */ 9384 if (depth > 1) { 9385 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9386 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); 9387 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9388 } 9389 } 9390 PetscFunctionReturn(PETSC_SUCCESS); 9391 } 9392 9393 /*@ 9394 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9395 9396 Collective 9397 9398 Input Parameters: 9399 + dm - The `DMPLEX` object 9400 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9401 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9402 9403 Level: developer 9404 9405 Notes: 9406 This is mainly intended for debugging/testing purposes. 9407 9408 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9409 9410 Extra roots can come from periodic cuts, where additional points appear on the boundary 9411 9412 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9413 @*/ 9414 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9415 { 9416 PetscInt l, nleaves, nroots, overlap; 9417 const PetscInt *locals; 9418 const PetscSFNode *remotes; 9419 PetscBool distributed; 9420 MPI_Comm comm; 9421 PetscMPIInt rank; 9422 9423 PetscFunctionBegin; 9424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9425 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9426 else pointSF = dm->sf; 9427 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9428 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9429 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9430 { 9431 PetscMPIInt mpiFlag; 9432 9433 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9434 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9435 } 9436 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9437 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9438 if (!distributed) { 9439 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); 9440 PetscFunctionReturn(PETSC_SUCCESS); 9441 } 9442 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); 9443 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9444 9445 /* Check SF graph is compatible with DMPlex chart */ 9446 { 9447 PetscInt pStart, pEnd, maxLeaf; 9448 9449 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9450 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9451 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9452 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9453 } 9454 9455 /* Check Point SF has no local points referenced */ 9456 for (l = 0; l < nleaves; l++) { 9457 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); 9458 } 9459 9460 /* Check there are no cells in interface */ 9461 if (!overlap) { 9462 PetscInt cellHeight, cStart, cEnd; 9463 9464 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9465 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9466 for (l = 0; l < nleaves; ++l) { 9467 const PetscInt point = locals ? locals[l] : l; 9468 9469 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9470 } 9471 } 9472 9473 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9474 { 9475 const PetscInt *rootdegree; 9476 9477 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9478 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9479 for (l = 0; l < nleaves; ++l) { 9480 const PetscInt point = locals ? locals[l] : l; 9481 const PetscInt *cone; 9482 PetscInt coneSize, c, idx; 9483 9484 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9485 PetscCall(DMPlexGetCone(dm, point, &cone)); 9486 for (c = 0; c < coneSize; ++c) { 9487 if (!rootdegree[cone[c]]) { 9488 if (locals) { 9489 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9490 } else { 9491 idx = (cone[c] < nleaves) ? cone[c] : -1; 9492 } 9493 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9494 } 9495 } 9496 } 9497 } 9498 PetscFunctionReturn(PETSC_SUCCESS); 9499 } 9500 9501 /*@ 9502 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9503 9504 Collective 9505 9506 Input Parameter: 9507 . dm - The `DMPLEX` object 9508 9509 Level: developer 9510 9511 Notes: 9512 This is mainly intended for debugging/testing purposes. 9513 9514 Other cell types which are disconnected would be caught by the symmetry and face checks. 9515 9516 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9517 9518 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9519 @*/ 9520 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9521 { 9522 PetscInt pStart, pEnd, vStart, vEnd; 9523 9524 PetscFunctionBegin; 9525 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9526 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9527 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9528 for (PetscInt v = vStart; v < vEnd; ++v) { 9529 PetscInt suppSize; 9530 9531 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9532 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9533 } 9534 PetscFunctionReturn(PETSC_SUCCESS); 9535 } 9536 9537 /*@ 9538 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9539 9540 Input Parameter: 9541 . dm - The `DMPLEX` object 9542 9543 Level: developer 9544 9545 Notes: 9546 This is a useful diagnostic when creating meshes programmatically. 9547 9548 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9549 9550 Currently does not include `DMPlexCheckCellShape()`. 9551 9552 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9553 @*/ 9554 PetscErrorCode DMPlexCheck(DM dm) 9555 { 9556 PetscInt cellHeight; 9557 9558 PetscFunctionBegin; 9559 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9560 PetscCall(DMPlexCheckSymmetry(dm)); 9561 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9562 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9563 PetscCall(DMPlexCheckGeometry(dm)); 9564 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9565 PetscCall(DMPlexCheckInterfaceCones(dm)); 9566 PetscCall(DMPlexCheckOrphanVertices(dm)); 9567 PetscFunctionReturn(PETSC_SUCCESS); 9568 } 9569 9570 typedef struct cell_stats { 9571 PetscReal min, max, sum, squaresum; 9572 PetscInt count; 9573 } cell_stats_t; 9574 9575 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9576 { 9577 PetscInt i, N = *len; 9578 9579 for (i = 0; i < N; i++) { 9580 cell_stats_t *A = (cell_stats_t *)a; 9581 cell_stats_t *B = (cell_stats_t *)b; 9582 9583 B->min = PetscMin(A->min, B->min); 9584 B->max = PetscMax(A->max, B->max); 9585 B->sum += A->sum; 9586 B->squaresum += A->squaresum; 9587 B->count += A->count; 9588 } 9589 } 9590 9591 /*@ 9592 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9593 9594 Collective 9595 9596 Input Parameters: 9597 + dm - The `DMPLEX` object 9598 . output - If true, statistics will be displayed on `stdout` 9599 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9600 9601 Level: developer 9602 9603 Notes: 9604 This is mainly intended for debugging/testing purposes. 9605 9606 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9607 9608 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9609 @*/ 9610 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9611 { 9612 DM dmCoarse; 9613 cell_stats_t stats, globalStats; 9614 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9615 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9616 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9617 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9618 PetscMPIInt rank, size; 9619 9620 PetscFunctionBegin; 9621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9622 stats.min = PETSC_MAX_REAL; 9623 stats.max = PETSC_MIN_REAL; 9624 stats.sum = stats.squaresum = 0.; 9625 stats.count = 0; 9626 9627 PetscCallMPI(MPI_Comm_size(comm, &size)); 9628 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9629 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9630 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9631 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9632 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9633 for (c = cStart; c < cEnd; c++) { 9634 PetscInt i; 9635 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9636 9637 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9638 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9639 for (i = 0; i < PetscSqr(cdim); ++i) { 9640 frobJ += J[i] * J[i]; 9641 frobInvJ += invJ[i] * invJ[i]; 9642 } 9643 cond2 = frobJ * frobInvJ; 9644 cond = PetscSqrtReal(cond2); 9645 9646 stats.min = PetscMin(stats.min, cond); 9647 stats.max = PetscMax(stats.max, cond); 9648 stats.sum += cond; 9649 stats.squaresum += cond2; 9650 stats.count++; 9651 if (output && cond > limit) { 9652 PetscSection coordSection; 9653 Vec coordsLocal; 9654 PetscScalar *coords = NULL; 9655 PetscInt Nv, d, clSize, cl, *closure = NULL; 9656 9657 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9658 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9659 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9660 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9661 for (i = 0; i < Nv / cdim; ++i) { 9662 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9663 for (d = 0; d < cdim; ++d) { 9664 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9665 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9666 } 9667 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9668 } 9669 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9670 for (cl = 0; cl < clSize * 2; cl += 2) { 9671 const PetscInt edge = closure[cl]; 9672 9673 if ((edge >= eStart) && (edge < eEnd)) { 9674 PetscReal len; 9675 9676 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9677 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9678 } 9679 } 9680 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9681 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9682 } 9683 } 9684 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9685 9686 if (size > 1) { 9687 PetscMPIInt blockLengths[2] = {4, 1}; 9688 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9689 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9690 MPI_Op statReduce; 9691 9692 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9693 PetscCallMPI(MPI_Type_commit(&statType)); 9694 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9695 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9696 PetscCallMPI(MPI_Op_free(&statReduce)); 9697 PetscCallMPI(MPI_Type_free(&statType)); 9698 } else { 9699 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9700 } 9701 if (rank == 0) { 9702 count = globalStats.count; 9703 min = globalStats.min; 9704 max = globalStats.max; 9705 mean = globalStats.sum / globalStats.count; 9706 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9707 } 9708 9709 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)); 9710 PetscCall(PetscFree2(J, invJ)); 9711 9712 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9713 if (dmCoarse) { 9714 PetscBool isplex; 9715 9716 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9717 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9718 } 9719 PetscFunctionReturn(PETSC_SUCCESS); 9720 } 9721 9722 /*@ 9723 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9724 orthogonal quality below given tolerance. 9725 9726 Collective 9727 9728 Input Parameters: 9729 + dm - The `DMPLEX` object 9730 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9731 - atol - [0, 1] Absolute tolerance for tagging cells. 9732 9733 Output Parameters: 9734 + OrthQual - `Vec` containing orthogonal quality per cell 9735 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9736 9737 Options Database Keys: 9738 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9739 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9740 9741 Level: intermediate 9742 9743 Notes: 9744 Orthogonal quality is given by the following formula\: 9745 9746 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9747 9748 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 9749 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9750 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9751 calculating the cosine of the angle between these vectors. 9752 9753 Orthogonal quality ranges from 1 (best) to 0 (worst). 9754 9755 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9756 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9757 9758 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9759 9760 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9761 @*/ 9762 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9763 { 9764 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9765 PetscInt *idx; 9766 PetscScalar *oqVals; 9767 const PetscScalar *cellGeomArr, *faceGeomArr; 9768 PetscReal *ci, *fi, *Ai; 9769 MPI_Comm comm; 9770 Vec cellgeom, facegeom; 9771 DM dmFace, dmCell; 9772 IS glob; 9773 ISLocalToGlobalMapping ltog; 9774 PetscViewer vwr; 9775 9776 PetscFunctionBegin; 9777 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9778 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9779 PetscAssertPointer(OrthQual, 4); 9780 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9781 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9782 PetscCall(DMGetDimension(dm, &nc)); 9783 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9784 { 9785 DMPlexInterpolatedFlag interpFlag; 9786 9787 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9788 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9789 PetscMPIInt rank; 9790 9791 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9792 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9793 } 9794 } 9795 if (OrthQualLabel) { 9796 PetscAssertPointer(OrthQualLabel, 5); 9797 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9798 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9799 } else { 9800 *OrthQualLabel = NULL; 9801 } 9802 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9803 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9804 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9805 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9806 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9807 PetscCall(VecCreate(comm, OrthQual)); 9808 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9809 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9810 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9811 PetscCall(VecSetUp(*OrthQual)); 9812 PetscCall(ISDestroy(&glob)); 9813 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9814 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9815 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9816 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9817 PetscCall(VecGetDM(cellgeom, &dmCell)); 9818 PetscCall(VecGetDM(facegeom, &dmFace)); 9819 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9820 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9821 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9822 PetscInt cellarr[2], *adj = NULL; 9823 PetscScalar *cArr, *fArr; 9824 PetscReal minvalc = 1.0, minvalf = 1.0; 9825 PetscFVCellGeom *cg; 9826 9827 idx[cellIter] = cell - cStart; 9828 cellarr[0] = cell; 9829 /* Make indexing into cellGeom easier */ 9830 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9831 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9832 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9833 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9834 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9835 PetscInt i; 9836 const PetscInt neigh = adj[cellneigh]; 9837 PetscReal normci = 0, normfi = 0, normai = 0; 9838 PetscFVCellGeom *cgneigh; 9839 PetscFVFaceGeom *fg; 9840 9841 /* Don't count ourselves in the neighbor list */ 9842 if (neigh == cell) continue; 9843 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9844 cellarr[1] = neigh; 9845 { 9846 PetscInt numcovpts; 9847 const PetscInt *covpts; 9848 9849 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9850 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9851 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9852 } 9853 9854 /* Compute c_i, f_i and their norms */ 9855 for (i = 0; i < nc; i++) { 9856 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9857 fi[i] = fg->centroid[i] - cg->centroid[i]; 9858 Ai[i] = fg->normal[i]; 9859 normci += PetscPowReal(ci[i], 2); 9860 normfi += PetscPowReal(fi[i], 2); 9861 normai += PetscPowReal(Ai[i], 2); 9862 } 9863 normci = PetscSqrtReal(normci); 9864 normfi = PetscSqrtReal(normfi); 9865 normai = PetscSqrtReal(normai); 9866 9867 /* Normalize and compute for each face-cell-normal pair */ 9868 for (i = 0; i < nc; i++) { 9869 ci[i] = ci[i] / normci; 9870 fi[i] = fi[i] / normfi; 9871 Ai[i] = Ai[i] / normai; 9872 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9873 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9874 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9875 } 9876 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9877 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9878 } 9879 PetscCall(PetscFree(adj)); 9880 PetscCall(PetscFree2(cArr, fArr)); 9881 /* Defer to cell if they're equal */ 9882 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9883 if (OrthQualLabel) { 9884 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9885 } 9886 } 9887 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9888 PetscCall(VecAssemblyBegin(*OrthQual)); 9889 PetscCall(VecAssemblyEnd(*OrthQual)); 9890 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9891 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9892 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9893 if (OrthQualLabel) { 9894 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9895 } 9896 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9897 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9898 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9899 PetscFunctionReturn(PETSC_SUCCESS); 9900 } 9901 9902 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9903 * interpolator construction */ 9904 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9905 { 9906 PetscSection section, newSection, gsection; 9907 PetscSF sf; 9908 PetscBool hasConstraints, ghasConstraints; 9909 9910 PetscFunctionBegin; 9911 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9912 PetscAssertPointer(odm, 2); 9913 PetscCall(DMGetLocalSection(dm, §ion)); 9914 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9915 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9916 if (!ghasConstraints) { 9917 PetscCall(PetscObjectReference((PetscObject)dm)); 9918 *odm = dm; 9919 PetscFunctionReturn(PETSC_SUCCESS); 9920 } 9921 PetscCall(DMClone(dm, odm)); 9922 PetscCall(DMCopyFields(dm, *odm)); 9923 PetscCall(DMGetLocalSection(*odm, &newSection)); 9924 PetscCall(DMGetPointSF(*odm, &sf)); 9925 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9926 PetscCall(DMSetGlobalSection(*odm, gsection)); 9927 PetscCall(PetscSectionDestroy(&gsection)); 9928 PetscFunctionReturn(PETSC_SUCCESS); 9929 } 9930 9931 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9932 { 9933 DM dmco, dmfo; 9934 Mat interpo; 9935 Vec rscale; 9936 Vec cglobalo, clocal; 9937 Vec fglobal, fglobalo, flocal; 9938 PetscBool regular; 9939 9940 PetscFunctionBegin; 9941 PetscCall(DMGetFullDM(dmc, &dmco)); 9942 PetscCall(DMGetFullDM(dmf, &dmfo)); 9943 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9944 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9945 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9946 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9947 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9948 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9949 PetscCall(VecSet(cglobalo, 0.)); 9950 PetscCall(VecSet(clocal, 0.)); 9951 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9952 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9953 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9954 PetscCall(VecSet(fglobal, 0.)); 9955 PetscCall(VecSet(fglobalo, 0.)); 9956 PetscCall(VecSet(flocal, 0.)); 9957 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9958 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9959 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9960 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9961 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9962 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9963 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9964 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9965 *shift = fglobal; 9966 PetscCall(VecDestroy(&flocal)); 9967 PetscCall(VecDestroy(&fglobalo)); 9968 PetscCall(VecDestroy(&clocal)); 9969 PetscCall(VecDestroy(&cglobalo)); 9970 PetscCall(VecDestroy(&rscale)); 9971 PetscCall(MatDestroy(&interpo)); 9972 PetscCall(DMDestroy(&dmfo)); 9973 PetscCall(DMDestroy(&dmco)); 9974 PetscFunctionReturn(PETSC_SUCCESS); 9975 } 9976 9977 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9978 { 9979 PetscObject shifto; 9980 Vec shift; 9981 9982 PetscFunctionBegin; 9983 if (!interp) { 9984 Vec rscale; 9985 9986 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9987 PetscCall(VecDestroy(&rscale)); 9988 } else { 9989 PetscCall(PetscObjectReference((PetscObject)interp)); 9990 } 9991 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9992 if (!shifto) { 9993 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9994 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9995 shifto = (PetscObject)shift; 9996 PetscCall(VecDestroy(&shift)); 9997 } 9998 shift = (Vec)shifto; 9999 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10000 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10001 PetscCall(MatDestroy(&interp)); 10002 PetscFunctionReturn(PETSC_SUCCESS); 10003 } 10004 10005 /* Pointwise interpolation 10006 Just code FEM for now 10007 u^f = I u^c 10008 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10009 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10010 I_{ij} = psi^f_i phi^c_j 10011 */ 10012 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10013 { 10014 PetscSection gsc, gsf; 10015 PetscInt m, n; 10016 void *ctx; 10017 DM cdm; 10018 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10019 10020 PetscFunctionBegin; 10021 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10022 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10023 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10024 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10025 10026 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10027 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10028 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10029 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10030 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10031 10032 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10033 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10034 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10035 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10036 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10037 if (scaling) { 10038 /* Use naive scaling */ 10039 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10040 } 10041 PetscFunctionReturn(PETSC_SUCCESS); 10042 } 10043 10044 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10045 { 10046 VecScatter ctx; 10047 10048 PetscFunctionBegin; 10049 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10050 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10051 PetscCall(VecScatterDestroy(&ctx)); 10052 PetscFunctionReturn(PETSC_SUCCESS); 10053 } 10054 10055 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[]) 10056 { 10057 const PetscInt Nc = uOff[1] - uOff[0]; 10058 PetscInt c; 10059 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10060 } 10061 10062 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 10063 { 10064 DM dmc; 10065 PetscDS ds; 10066 Vec ones, locmass; 10067 IS cellIS; 10068 PetscFormKey key; 10069 PetscInt depth; 10070 10071 PetscFunctionBegin; 10072 PetscCall(DMClone(dm, &dmc)); 10073 PetscCall(DMCopyDisc(dm, dmc)); 10074 PetscCall(DMGetDS(dmc, &ds)); 10075 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10076 PetscCall(DMCreateGlobalVector(dmc, mass)); 10077 PetscCall(DMGetLocalVector(dmc, &ones)); 10078 PetscCall(DMGetLocalVector(dmc, &locmass)); 10079 PetscCall(DMPlexGetDepth(dmc, &depth)); 10080 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10081 PetscCall(VecSet(locmass, 0.0)); 10082 PetscCall(VecSet(ones, 1.0)); 10083 key.label = NULL; 10084 key.value = 0; 10085 key.field = 0; 10086 key.part = 0; 10087 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10088 PetscCall(ISDestroy(&cellIS)); 10089 PetscCall(VecSet(*mass, 0.0)); 10090 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10091 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10092 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10093 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10094 PetscCall(DMDestroy(&dmc)); 10095 PetscFunctionReturn(PETSC_SUCCESS); 10096 } 10097 10098 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10099 { 10100 PetscSection gsc, gsf; 10101 PetscInt m, n; 10102 void *ctx; 10103 DM cdm; 10104 PetscBool regular; 10105 10106 PetscFunctionBegin; 10107 if (dmFine == dmCoarse) { 10108 DM dmc; 10109 PetscDS ds; 10110 PetscWeakForm wf; 10111 Vec u; 10112 IS cellIS; 10113 PetscFormKey key; 10114 PetscInt depth; 10115 10116 PetscCall(DMClone(dmFine, &dmc)); 10117 PetscCall(DMCopyDisc(dmFine, dmc)); 10118 PetscCall(DMGetDS(dmc, &ds)); 10119 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10120 PetscCall(PetscWeakFormClear(wf)); 10121 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10122 PetscCall(DMCreateMatrix(dmc, mass)); 10123 PetscCall(DMGetLocalVector(dmc, &u)); 10124 PetscCall(DMPlexGetDepth(dmc, &depth)); 10125 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10126 PetscCall(MatZeroEntries(*mass)); 10127 key.label = NULL; 10128 key.value = 0; 10129 key.field = 0; 10130 key.part = 0; 10131 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10132 PetscCall(ISDestroy(&cellIS)); 10133 PetscCall(DMRestoreLocalVector(dmc, &u)); 10134 PetscCall(DMDestroy(&dmc)); 10135 } else { 10136 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10137 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10138 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10139 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10140 10141 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10142 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10143 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10144 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10145 10146 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10147 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10148 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10149 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10150 } 10151 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10152 PetscFunctionReturn(PETSC_SUCCESS); 10153 } 10154 10155 /*@ 10156 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10157 10158 Input Parameter: 10159 . dm - The `DMPLEX` object 10160 10161 Output Parameter: 10162 . regular - The flag 10163 10164 Level: intermediate 10165 10166 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10167 @*/ 10168 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10169 { 10170 PetscFunctionBegin; 10171 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10172 PetscAssertPointer(regular, 2); 10173 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10174 PetscFunctionReturn(PETSC_SUCCESS); 10175 } 10176 10177 /*@ 10178 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10179 10180 Input Parameters: 10181 + dm - The `DMPLEX` object 10182 - regular - The flag 10183 10184 Level: intermediate 10185 10186 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10187 @*/ 10188 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10189 { 10190 PetscFunctionBegin; 10191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10192 ((DM_Plex *)dm->data)->regularRefinement = regular; 10193 PetscFunctionReturn(PETSC_SUCCESS); 10194 } 10195 10196 /*@ 10197 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10198 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10199 10200 Not Collective 10201 10202 Input Parameter: 10203 . dm - The `DMPLEX` object 10204 10205 Output Parameters: 10206 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10207 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10208 10209 Level: intermediate 10210 10211 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10212 @*/ 10213 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10214 { 10215 DM_Plex *plex = (DM_Plex *)dm->data; 10216 10217 PetscFunctionBegin; 10218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10219 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10220 if (anchorSection) *anchorSection = plex->anchorSection; 10221 if (anchorIS) *anchorIS = plex->anchorIS; 10222 PetscFunctionReturn(PETSC_SUCCESS); 10223 } 10224 10225 /*@ 10226 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10227 10228 Collective 10229 10230 Input Parameters: 10231 + dm - The `DMPLEX` object 10232 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10233 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10234 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10235 10236 Level: intermediate 10237 10238 Notes: 10239 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10240 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10241 combination of other points' degrees of freedom. 10242 10243 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10244 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10245 10246 The reference counts of `anchorSection` and `anchorIS` are incremented. 10247 10248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10249 @*/ 10250 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10251 { 10252 DM_Plex *plex = (DM_Plex *)dm->data; 10253 PetscMPIInt result; 10254 10255 PetscFunctionBegin; 10256 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10257 if (anchorSection) { 10258 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10259 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10260 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10261 } 10262 if (anchorIS) { 10263 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10264 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10265 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10266 } 10267 10268 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10269 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10270 plex->anchorSection = anchorSection; 10271 10272 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10273 PetscCall(ISDestroy(&plex->anchorIS)); 10274 plex->anchorIS = anchorIS; 10275 10276 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10277 PetscInt size, a, pStart, pEnd; 10278 const PetscInt *anchors; 10279 10280 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10281 PetscCall(ISGetLocalSize(anchorIS, &size)); 10282 PetscCall(ISGetIndices(anchorIS, &anchors)); 10283 for (a = 0; a < size; a++) { 10284 PetscInt p; 10285 10286 p = anchors[a]; 10287 if (p >= pStart && p < pEnd) { 10288 PetscInt dof; 10289 10290 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10291 if (dof) { 10292 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10293 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10294 } 10295 } 10296 } 10297 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10298 } 10299 /* reset the generic constraints */ 10300 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10301 PetscFunctionReturn(PETSC_SUCCESS); 10302 } 10303 10304 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10305 { 10306 PetscSection anchorSection; 10307 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10308 10309 PetscFunctionBegin; 10310 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10311 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10312 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10313 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10314 if (numFields) { 10315 PetscInt f; 10316 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10317 10318 for (f = 0; f < numFields; f++) { 10319 PetscInt numComp; 10320 10321 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10322 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10323 } 10324 } 10325 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10326 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10327 pStart = PetscMax(pStart, sStart); 10328 pEnd = PetscMin(pEnd, sEnd); 10329 pEnd = PetscMax(pStart, pEnd); 10330 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10331 for (p = pStart; p < pEnd; p++) { 10332 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10333 if (dof) { 10334 PetscCall(PetscSectionGetDof(section, p, &dof)); 10335 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10336 for (f = 0; f < numFields; f++) { 10337 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10338 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10339 } 10340 } 10341 } 10342 PetscCall(PetscSectionSetUp(*cSec)); 10343 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10344 PetscFunctionReturn(PETSC_SUCCESS); 10345 } 10346 10347 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10348 { 10349 PetscSection aSec; 10350 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10351 const PetscInt *anchors; 10352 PetscInt numFields, f; 10353 IS aIS; 10354 MatType mtype; 10355 PetscBool iscuda, iskokkos; 10356 10357 PetscFunctionBegin; 10358 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10359 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10360 PetscCall(PetscSectionGetStorageSize(section, &n)); 10361 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10362 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10363 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10364 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10365 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10366 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10367 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10368 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10369 else mtype = MATSEQAIJ; 10370 PetscCall(MatSetType(*cMat, mtype)); 10371 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10372 PetscCall(ISGetIndices(aIS, &anchors)); 10373 /* cSec will be a subset of aSec and section */ 10374 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10375 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10376 PetscCall(PetscMalloc1(m + 1, &i)); 10377 i[0] = 0; 10378 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10379 for (p = pStart; p < pEnd; p++) { 10380 PetscInt rDof, rOff, r; 10381 10382 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10383 if (!rDof) continue; 10384 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10385 if (numFields) { 10386 for (f = 0; f < numFields; f++) { 10387 annz = 0; 10388 for (r = 0; r < rDof; r++) { 10389 a = anchors[rOff + r]; 10390 if (a < sStart || a >= sEnd) continue; 10391 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10392 annz += aDof; 10393 } 10394 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10395 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10396 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10397 } 10398 } else { 10399 annz = 0; 10400 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10401 for (q = 0; q < dof; q++) { 10402 a = anchors[rOff + q]; 10403 if (a < sStart || a >= sEnd) continue; 10404 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10405 annz += aDof; 10406 } 10407 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10408 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10409 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10410 } 10411 } 10412 nnz = i[m]; 10413 PetscCall(PetscMalloc1(nnz, &j)); 10414 offset = 0; 10415 for (p = pStart; p < pEnd; p++) { 10416 if (numFields) { 10417 for (f = 0; f < numFields; f++) { 10418 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10419 for (q = 0; q < dof; q++) { 10420 PetscInt rDof, rOff, r; 10421 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10422 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10423 for (r = 0; r < rDof; r++) { 10424 PetscInt s; 10425 10426 a = anchors[rOff + r]; 10427 if (a < sStart || a >= sEnd) continue; 10428 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10429 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10430 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10431 } 10432 } 10433 } 10434 } else { 10435 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10436 for (q = 0; q < dof; q++) { 10437 PetscInt rDof, rOff, r; 10438 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10439 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10440 for (r = 0; r < rDof; r++) { 10441 PetscInt s; 10442 10443 a = anchors[rOff + r]; 10444 if (a < sStart || a >= sEnd) continue; 10445 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10446 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10447 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10448 } 10449 } 10450 } 10451 } 10452 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10453 PetscCall(PetscFree(i)); 10454 PetscCall(PetscFree(j)); 10455 PetscCall(ISRestoreIndices(aIS, &anchors)); 10456 PetscFunctionReturn(PETSC_SUCCESS); 10457 } 10458 10459 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10460 { 10461 DM_Plex *plex = (DM_Plex *)dm->data; 10462 PetscSection anchorSection, section, cSec; 10463 Mat cMat; 10464 10465 PetscFunctionBegin; 10466 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10467 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10468 if (anchorSection) { 10469 PetscInt Nf; 10470 10471 PetscCall(DMGetLocalSection(dm, §ion)); 10472 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10473 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10474 PetscCall(DMGetNumFields(dm, &Nf)); 10475 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10476 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10477 PetscCall(PetscSectionDestroy(&cSec)); 10478 PetscCall(MatDestroy(&cMat)); 10479 } 10480 PetscFunctionReturn(PETSC_SUCCESS); 10481 } 10482 10483 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10484 { 10485 IS subis; 10486 PetscSection section, subsection; 10487 10488 PetscFunctionBegin; 10489 PetscCall(DMGetLocalSection(dm, §ion)); 10490 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10491 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10492 /* Create subdomain */ 10493 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10494 /* Create submodel */ 10495 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10496 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10497 PetscCall(DMSetLocalSection(*subdm, subsection)); 10498 PetscCall(PetscSectionDestroy(&subsection)); 10499 PetscCall(DMCopyDisc(dm, *subdm)); 10500 /* Create map from submodel to global model */ 10501 if (is) { 10502 PetscSection sectionGlobal, subsectionGlobal; 10503 IS spIS; 10504 const PetscInt *spmap; 10505 PetscInt *subIndices; 10506 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10507 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10508 10509 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10510 PetscCall(ISGetIndices(spIS, &spmap)); 10511 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10512 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10513 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10514 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10515 for (p = pStart; p < pEnd; ++p) { 10516 PetscInt gdof, pSubSize = 0; 10517 10518 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10519 if (gdof > 0) { 10520 for (f = 0; f < Nf; ++f) { 10521 PetscInt fdof, fcdof; 10522 10523 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10524 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10525 pSubSize += fdof - fcdof; 10526 } 10527 subSize += pSubSize; 10528 if (pSubSize) { 10529 if (bs < 0) { 10530 bs = pSubSize; 10531 } else if (bs != pSubSize) { 10532 /* Layout does not admit a pointwise block size */ 10533 bs = 1; 10534 } 10535 } 10536 } 10537 } 10538 /* Must have same blocksize on all procs (some might have no points) */ 10539 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10540 bsLocal[1] = bs; 10541 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10542 if (bsMinMax[0] != bsMinMax[1]) { 10543 bs = 1; 10544 } else { 10545 bs = bsMinMax[0]; 10546 } 10547 PetscCall(PetscMalloc1(subSize, &subIndices)); 10548 for (p = pStart; p < pEnd; ++p) { 10549 PetscInt gdof, goff; 10550 10551 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10552 if (gdof > 0) { 10553 const PetscInt point = spmap[p]; 10554 10555 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10556 for (f = 0; f < Nf; ++f) { 10557 PetscInt fdof, fcdof, fc, f2, poff = 0; 10558 10559 /* Can get rid of this loop by storing field information in the global section */ 10560 for (f2 = 0; f2 < f; ++f2) { 10561 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10562 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10563 poff += fdof - fcdof; 10564 } 10565 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10566 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10567 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10568 } 10569 } 10570 } 10571 PetscCall(ISRestoreIndices(spIS, &spmap)); 10572 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10573 if (bs > 1) { 10574 /* We need to check that the block size does not come from non-contiguous fields */ 10575 PetscInt i, j, set = 1; 10576 for (i = 0; i < subSize; i += bs) { 10577 for (j = 0; j < bs; ++j) { 10578 if (subIndices[i + j] != subIndices[i] + j) { 10579 set = 0; 10580 break; 10581 } 10582 } 10583 } 10584 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10585 } 10586 /* Attach nullspace */ 10587 for (f = 0; f < Nf; ++f) { 10588 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10589 if ((*subdm)->nullspaceConstructors[f]) break; 10590 } 10591 if (f < Nf) { 10592 MatNullSpace nullSpace; 10593 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10594 10595 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10596 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10597 } 10598 } 10599 PetscFunctionReturn(PETSC_SUCCESS); 10600 } 10601 10602 /*@ 10603 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10604 10605 Input Parameters: 10606 + dm - The `DM` 10607 - dummy - unused argument 10608 10609 Options Database Key: 10610 . -dm_plex_monitor_throughput - Activate the monitor 10611 10612 Level: developer 10613 10614 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10615 @*/ 10616 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10617 { 10618 PetscLogHandler default_handler; 10619 10620 PetscFunctionBegin; 10621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10622 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10623 if (default_handler) { 10624 PetscLogEvent event; 10625 PetscEventPerfInfo eventInfo; 10626 PetscReal cellRate, flopRate; 10627 PetscInt cStart, cEnd, Nf, N; 10628 const char *name; 10629 10630 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10631 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10632 PetscCall(DMGetNumFields(dm, &Nf)); 10633 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10634 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10635 N = (cEnd - cStart) * Nf * eventInfo.count; 10636 flopRate = eventInfo.flops / eventInfo.time; 10637 cellRate = N / eventInfo.time; 10638 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))); 10639 } else { 10640 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."); 10641 } 10642 PetscFunctionReturn(PETSC_SUCCESS); 10643 } 10644