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