1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 89 90 PetscFunctionBegin; 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 93 PetscCall(ISGetLocalSize(valueIS, &Nct)); 94 PetscCall(ISGetIndices(valueIS, &ctypes)); 95 if (!Nct) cS = cE = 0; 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 } 114 PetscCall(ISDestroy(&valueIS)); 115 // Reset label for fast lookup 116 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 117 if (cStart) *cStart = cS; 118 if (cEnd) *cEnd = cE; 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 123 { 124 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 125 PetscInt *sStart, *sEnd; 126 PetscViewerVTKFieldType *ft; 127 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 128 DMLabel depthLabel, ctLabel; 129 130 PetscFunctionBegin; 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 } 162 163 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 164 *types = 0; 165 166 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 167 if (globalvcdof[c]) ++(*types); 168 } 169 170 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 171 t = 0; 172 if (globalvcdof[DM_NUM_POLYTOPES]) { 173 sStart[t] = vStart; 174 sEnd[t] = vEnd; 175 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 176 ++t; 177 } 178 179 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 180 if (globalvcdof[c]) { 181 const DMPolytopeType ict = (DMPolytopeType)c; 182 183 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 184 sStart[t] = cStart; 185 sEnd[t] = cEnd; 186 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 187 ++t; 188 } 189 } 190 191 if (!*types) { 192 if (field >= 0) { 193 const char *fieldname; 194 195 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 196 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 197 } else { 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 199 } 200 } 201 202 *ssStart = sStart; 203 *ssEnd = sEnd; 204 *sft = ft; 205 PetscFunctionReturn(PETSC_SUCCESS); 206 } 207 208 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 209 { 210 PetscFunctionBegin; 211 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 216 { 217 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 218 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 219 220 PetscFunctionBegin; 221 *ft = PETSC_VTK_INVALID; 222 PetscCall(DMGetCoordinateDim(dm, &cdim)); 223 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 224 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 225 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 226 if (field >= 0) { 227 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 228 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 229 } else { 230 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 231 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 232 } 233 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 234 if (globalvcdof[0]) { 235 *sStart = vStart; 236 *sEnd = vEnd; 237 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 238 else *ft = PETSC_VTK_POINT_FIELD; 239 } else if (globalvcdof[1]) { 240 *sStart = cStart; 241 *sEnd = cEnd; 242 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 243 else *ft = PETSC_VTK_CELL_FIELD; 244 } else { 245 if (field >= 0) { 246 const char *fieldname; 247 248 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 249 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 250 } else { 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 252 } 253 } 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 /*@ 258 DMPlexVecView1D - Plot many 1D solutions on the same line graph 259 260 Collective 261 262 Input Parameters: 263 + dm - The `DMPLEX` object 264 . n - The number of vectors 265 . u - The array of local vectors 266 - viewer - The `PetscViewer` 267 268 Level: advanced 269 270 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 271 @*/ 272 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 273 { 274 PetscDS ds; 275 PetscDraw draw = NULL; 276 PetscDrawLG lg; 277 Vec coordinates; 278 const PetscScalar *coords, **sol; 279 PetscReal *vals; 280 PetscInt *Nc; 281 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 282 char **names; 283 284 PetscFunctionBegin; 285 PetscCall(DMGetDS(dm, &ds)); 286 PetscCall(PetscDSGetNumFields(ds, &Nf)); 287 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 288 PetscCall(PetscDSGetComponents(ds, &Nc)); 289 290 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 291 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 292 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 293 294 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 295 for (i = 0, l = 0; i < n; ++i) { 296 const char *vname; 297 298 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 299 for (f = 0; f < Nf; ++f) { 300 PetscObject disc; 301 const char *fname; 302 char tmpname[PETSC_MAX_PATH_LEN]; 303 304 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 305 /* TODO Create names for components */ 306 for (c = 0; c < Nc[f]; ++c, ++l) { 307 PetscCall(PetscObjectGetName(disc, &fname)); 308 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 309 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 311 PetscCall(PetscStrallocpy(tmpname, &names[l])); 312 } 313 } 314 } 315 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 316 /* Just add P_1 support for now */ 317 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 318 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 319 PetscCall(VecGetArrayRead(coordinates, &coords)); 320 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 321 for (v = vStart; v < vEnd; ++v) { 322 PetscScalar *x, *svals; 323 324 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 325 for (i = 0; i < n; ++i) { 326 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 327 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 328 } 329 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 330 } 331 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 332 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 333 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 334 PetscCall(PetscFree3(sol, names, vals)); 335 336 PetscCall(PetscDrawLGDraw(lg)); 337 PetscCall(PetscDrawLGDestroy(&lg)); 338 PetscFunctionReturn(PETSC_SUCCESS); 339 } 340 341 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 342 { 343 DM dm; 344 345 PetscFunctionBegin; 346 PetscCall(VecGetDM(u, &dm)); 347 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 352 { 353 DM dm; 354 PetscSection s; 355 PetscDraw draw, popup; 356 DM cdm; 357 PetscSection coordSection; 358 Vec coordinates; 359 const PetscScalar *array; 360 PetscReal lbound[3], ubound[3]; 361 PetscReal vbound[2], time; 362 PetscBool flg; 363 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 364 const char *name; 365 char title[PETSC_MAX_PATH_LEN]; 366 367 PetscFunctionBegin; 368 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 369 PetscCall(VecGetDM(v, &dm)); 370 PetscCall(DMGetCoordinateDim(dm, &dim)); 371 PetscCall(DMGetLocalSection(dm, &s)); 372 PetscCall(PetscSectionGetNumFields(s, &Nf)); 373 PetscCall(DMGetCoarsenLevel(dm, &level)); 374 PetscCall(DMGetCoordinateDM(dm, &cdm)); 375 PetscCall(DMGetLocalSection(cdm, &coordSection)); 376 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 377 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 378 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 379 380 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 381 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 382 383 PetscCall(VecGetLocalSize(coordinates, &N)); 384 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 385 PetscCall(PetscDrawClear(draw)); 386 387 /* Could implement something like DMDASelectFields() */ 388 for (f = 0; f < Nf; ++f) { 389 DM fdm = dm; 390 Vec fv = v; 391 IS fis; 392 char prefix[PETSC_MAX_PATH_LEN]; 393 const char *fname; 394 395 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 396 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 397 398 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 399 else prefix[0] = '\0'; 400 if (Nf > 1) { 401 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 402 PetscCall(VecGetSubVector(v, fis, &fv)); 403 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 404 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 405 } 406 for (comp = 0; comp < Nc; ++comp, ++w) { 407 PetscInt nmax = 2; 408 409 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 410 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 411 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 412 PetscCall(PetscDrawSetTitle(draw, title)); 413 414 /* TODO Get max and min only for this component */ 415 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 416 if (!flg) { 417 PetscCall(VecMin(fv, NULL, &vbound[0])); 418 PetscCall(VecMax(fv, NULL, &vbound[1])); 419 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 420 } 421 422 PetscCall(PetscDrawGetPopup(draw, &popup)); 423 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 424 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 425 PetscCall(VecGetArrayRead(fv, &array)); 426 for (c = cStart; c < cEnd; ++c) { 427 PetscScalar *coords = NULL, *a = NULL; 428 const PetscScalar *coords_arr; 429 PetscBool isDG; 430 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 431 432 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 433 if (a) { 434 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 435 color[1] = color[2] = color[3] = color[0]; 436 } else { 437 PetscScalar *vals = NULL; 438 PetscInt numVals, va; 439 440 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 441 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 442 switch (numVals / Nc) { 443 case 3: /* P1 Triangle */ 444 case 4: /* P1 Quadrangle */ 445 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 446 break; 447 case 6: /* P2 Triangle */ 448 case 8: /* P2 Quadrangle */ 449 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 450 break; 451 default: 452 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 453 } 454 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 455 } 456 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 457 switch (numCoords) { 458 case 6: 459 case 12: /* Localized triangle */ 460 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 461 break; 462 case 8: 463 case 16: /* Localized quadrilateral */ 464 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 465 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 466 break; 467 default: 468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 469 } 470 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 471 } 472 PetscCall(VecRestoreArrayRead(fv, &array)); 473 PetscCall(PetscDrawFlush(draw)); 474 PetscCall(PetscDrawPause(draw)); 475 PetscCall(PetscDrawSave(draw)); 476 } 477 if (Nf > 1) { 478 PetscCall(VecRestoreSubVector(v, fis, &fv)); 479 PetscCall(ISDestroy(&fis)); 480 PetscCall(DMDestroy(&fdm)); 481 } 482 } 483 PetscFunctionReturn(PETSC_SUCCESS); 484 } 485 486 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 487 { 488 DM dm; 489 PetscDraw draw; 490 PetscInt dim; 491 PetscBool isnull; 492 493 PetscFunctionBegin; 494 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 495 PetscCall(PetscDrawIsNull(draw, &isnull)); 496 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 497 498 PetscCall(VecGetDM(v, &dm)); 499 PetscCall(DMGetCoordinateDim(dm, &dim)); 500 switch (dim) { 501 case 1: 502 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 503 break; 504 case 2: 505 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 506 break; 507 default: 508 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 509 } 510 PetscFunctionReturn(PETSC_SUCCESS); 511 } 512 513 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 514 { 515 DM dm; 516 Vec locv; 517 const char *name; 518 PetscSection section; 519 PetscInt pStart, pEnd; 520 PetscInt numFields; 521 PetscViewerVTKFieldType ft; 522 523 PetscFunctionBegin; 524 PetscCall(VecGetDM(v, &dm)); 525 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 526 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 527 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 528 PetscCall(VecCopy(v, locv)); 529 PetscCall(DMGetLocalSection(dm, §ion)); 530 PetscCall(PetscSectionGetNumFields(section, &numFields)); 531 if (!numFields) { 532 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 533 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 534 } else { 535 PetscInt f; 536 537 for (f = 0; f < numFields; f++) { 538 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 539 if (ft == PETSC_VTK_INVALID) continue; 540 PetscCall(PetscObjectReference((PetscObject)locv)); 541 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 542 } 543 PetscCall(VecDestroy(&locv)); 544 } 545 PetscFunctionReturn(PETSC_SUCCESS); 546 } 547 548 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 549 { 550 DM dm; 551 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 552 553 PetscFunctionBegin; 554 PetscCall(VecGetDM(v, &dm)); 555 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 561 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 562 PetscInt i, numFields; 563 PetscObject fe; 564 PetscBool fem = PETSC_FALSE; 565 Vec locv = v; 566 const char *name; 567 PetscInt step; 568 PetscReal time; 569 570 PetscCall(DMGetNumFields(dm, &numFields)); 571 for (i = 0; i < numFields; i++) { 572 PetscCall(DMGetField(dm, i, NULL, &fe)); 573 if (fe->classid == PETSCFE_CLASSID) { 574 fem = PETSC_TRUE; 575 break; 576 } 577 } 578 if (fem) { 579 PetscObject isZero; 580 581 PetscCall(DMGetLocalVector(dm, &locv)); 582 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 583 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 584 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 585 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 586 PetscCall(VecCopy(v, locv)); 587 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 588 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 589 } 590 if (isvtk) { 591 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 592 } else if (ishdf5) { 593 #if defined(PETSC_HAVE_HDF5) 594 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 595 #else 596 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 597 #endif 598 } else if (isdraw) { 599 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 600 } else if (isglvis) { 601 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 602 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 603 PetscCall(VecView_GLVis(locv, viewer)); 604 } else if (iscgns) { 605 #if defined(PETSC_HAVE_CGNS) 606 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 607 #else 608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 609 #endif 610 } 611 if (fem) { 612 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 613 PetscCall(DMRestoreLocalVector(dm, &locv)); 614 } 615 } else { 616 PetscBool isseq; 617 618 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 619 if (isseq) PetscCall(VecView_Seq(v, viewer)); 620 else PetscCall(VecView_MPI(v, viewer)); 621 } 622 PetscFunctionReturn(PETSC_SUCCESS); 623 } 624 625 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 626 { 627 DM dm; 628 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 629 630 PetscFunctionBegin; 631 PetscCall(VecGetDM(v, &dm)); 632 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 633 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 639 if (isvtk || isdraw || isglvis || iscgns) { 640 Vec locv; 641 PetscObject isZero; 642 const char *name; 643 644 PetscCall(DMGetLocalVector(dm, &locv)); 645 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 646 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 647 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 648 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 649 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 650 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 651 PetscCall(VecView_Plex_Local(locv, viewer)); 652 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 653 PetscCall(DMRestoreLocalVector(dm, &locv)); 654 } else if (ishdf5) { 655 #if defined(PETSC_HAVE_HDF5) 656 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 657 #else 658 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 659 #endif 660 } else if (isexodusii) { 661 #if defined(PETSC_HAVE_EXODUSII) 662 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 663 #else 664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 665 #endif 666 } else { 667 PetscBool isseq; 668 669 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 670 if (isseq) PetscCall(VecView_Seq(v, viewer)); 671 else PetscCall(VecView_MPI(v, viewer)); 672 } 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 677 { 678 DM dm; 679 MPI_Comm comm; 680 PetscViewerFormat format; 681 Vec v; 682 PetscBool isvtk, ishdf5; 683 684 PetscFunctionBegin; 685 PetscCall(VecGetDM(originalv, &dm)); 686 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 687 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 688 PetscCall(PetscViewerGetFormat(viewer, &format)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 691 if (format == PETSC_VIEWER_NATIVE) { 692 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 693 /* this need a better fix */ 694 if (dm->useNatural) { 695 if (dm->sfNatural) { 696 const char *vecname; 697 PetscInt n, nroots; 698 699 PetscCall(VecGetLocalSize(originalv, &n)); 700 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 701 if (n == nroots) { 702 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 703 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 704 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 705 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 706 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 707 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 709 } else v = originalv; 710 } else v = originalv; 711 712 if (ishdf5) { 713 #if defined(PETSC_HAVE_HDF5) 714 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 715 #else 716 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 717 #endif 718 } else if (isvtk) { 719 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 720 } else { 721 PetscBool isseq; 722 723 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 724 if (isseq) PetscCall(VecView_Seq(v, viewer)); 725 else PetscCall(VecView_MPI(v, viewer)); 726 } 727 if (v != originalv) PetscCall(VecDestroy(&v)); 728 PetscFunctionReturn(PETSC_SUCCESS); 729 } 730 731 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 732 { 733 DM dm; 734 PetscBool ishdf5; 735 736 PetscFunctionBegin; 737 PetscCall(VecGetDM(v, &dm)); 738 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 739 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 740 if (ishdf5) { 741 DM dmBC; 742 Vec gv; 743 const char *name; 744 745 PetscCall(DMGetOutputDM(dm, &dmBC)); 746 PetscCall(DMGetGlobalVector(dmBC, &gv)); 747 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 748 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 749 PetscCall(VecLoad_Default(gv, viewer)); 750 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 751 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 753 } else PetscCall(VecLoad_Default(v, viewer)); 754 PetscFunctionReturn(PETSC_SUCCESS); 755 } 756 757 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 758 { 759 DM dm; 760 PetscBool ishdf5, isexodusii; 761 762 PetscFunctionBegin; 763 PetscCall(VecGetDM(v, &dm)); 764 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 765 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 767 if (ishdf5) { 768 #if defined(PETSC_HAVE_HDF5) 769 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 770 #else 771 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 772 #endif 773 } else if (isexodusii) { 774 #if defined(PETSC_HAVE_EXODUSII) 775 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 776 #else 777 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 778 #endif 779 } else PetscCall(VecLoad_Default(v, viewer)); 780 PetscFunctionReturn(PETSC_SUCCESS); 781 } 782 783 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 784 { 785 DM dm; 786 PetscViewerFormat format; 787 PetscBool ishdf5; 788 789 PetscFunctionBegin; 790 PetscCall(VecGetDM(originalv, &dm)); 791 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 792 PetscCall(PetscViewerGetFormat(viewer, &format)); 793 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 794 if (format == PETSC_VIEWER_NATIVE) { 795 if (dm->useNatural) { 796 if (dm->sfNatural) { 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 Vec v; 800 const char *vecname; 801 802 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 803 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 804 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 805 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 806 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 807 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 808 PetscCall(VecDestroy(&v)); 809 #else 810 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 811 #endif 812 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 813 } 814 } else PetscCall(VecLoad_Default(originalv, viewer)); 815 } 816 PetscFunctionReturn(PETSC_SUCCESS); 817 } 818 819 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 820 { 821 PetscSection coordSection; 822 Vec coordinates; 823 DMLabel depthLabel, celltypeLabel; 824 const char *name[4]; 825 const PetscScalar *a; 826 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 827 828 PetscFunctionBegin; 829 PetscCall(DMGetDimension(dm, &dim)); 830 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 831 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 832 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 833 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 834 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 835 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 836 PetscCall(VecGetArrayRead(coordinates, &a)); 837 name[0] = "vertex"; 838 name[1] = "edge"; 839 name[dim - 1] = "face"; 840 name[dim] = "cell"; 841 for (c = cStart; c < cEnd; ++c) { 842 PetscInt *closure = NULL; 843 PetscInt closureSize, cl, ct; 844 845 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 846 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 847 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 848 PetscCall(PetscViewerASCIIPushTab(viewer)); 849 for (cl = 0; cl < closureSize * 2; cl += 2) { 850 PetscInt point = closure[cl], depth, dof, off, d, p; 851 852 if ((point < pStart) || (point >= pEnd)) continue; 853 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 854 if (!dof) continue; 855 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 856 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 858 for (p = 0; p < dof / dim; ++p) { 859 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 860 for (d = 0; d < dim; ++d) { 861 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 862 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 863 } 864 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 865 } 866 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 867 } 868 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 869 PetscCall(PetscViewerASCIIPopTab(viewer)); 870 } 871 PetscCall(VecRestoreArrayRead(coordinates, &a)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 typedef enum { 876 CS_CARTESIAN, 877 CS_POLAR, 878 CS_CYLINDRICAL, 879 CS_SPHERICAL 880 } CoordSystem; 881 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 882 883 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 884 { 885 PetscInt i; 886 887 PetscFunctionBegin; 888 if (dim > 3) { 889 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 890 } else { 891 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 892 893 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 894 switch (cs) { 895 case CS_CARTESIAN: 896 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 897 break; 898 case CS_POLAR: 899 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 900 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 901 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 902 break; 903 case CS_CYLINDRICAL: 904 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 905 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 906 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 907 trcoords[2] = coords[2]; 908 break; 909 case CS_SPHERICAL: 910 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 911 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 912 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 913 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 914 break; 915 } 916 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 917 } 918 PetscFunctionReturn(PETSC_SUCCESS); 919 } 920 921 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 922 { 923 DM_Plex *mesh = (DM_Plex *)dm->data; 924 DM cdm, cdmCell; 925 PetscSection coordSection, coordSectionCell; 926 Vec coordinates, coordinatesCell; 927 PetscViewerFormat format; 928 929 PetscFunctionBegin; 930 PetscCall(PetscViewerGetFormat(viewer, &format)); 931 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 932 const char *name; 933 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 934 PetscInt pStart, pEnd, p, numLabels, l; 935 PetscMPIInt rank, size; 936 937 PetscCall(DMGetCoordinateDM(dm, &cdm)); 938 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 939 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 940 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 941 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 942 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 943 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 944 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 945 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 946 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 947 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 948 PetscCall(DMGetDimension(dm, &dim)); 949 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 950 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 951 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 952 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 953 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 954 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 955 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 956 for (p = pStart; p < pEnd; ++p) { 957 PetscInt dof, off, s; 958 959 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 960 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 961 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 962 } 963 PetscCall(PetscViewerFlush(viewer)); 964 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 965 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 966 for (p = pStart; p < pEnd; ++p) { 967 PetscInt dof, off, c; 968 969 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 970 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 971 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 972 } 973 PetscCall(PetscViewerFlush(viewer)); 974 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 975 if (coordSection && coordinates) { 976 CoordSystem cs = CS_CARTESIAN; 977 const PetscScalar *array, *arrayCell = NULL; 978 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 979 PetscMPIInt rank; 980 const char *name; 981 982 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 983 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 984 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 985 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 986 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 987 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 988 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 989 pStart = PetscMin(pvStart, pcStart); 990 pEnd = PetscMax(pvEnd, pcEnd); 991 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 992 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 994 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 995 996 PetscCall(VecGetArrayRead(coordinates, &array)); 997 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 998 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 999 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1000 for (p = pStart; p < pEnd; ++p) { 1001 PetscInt dof, off; 1002 1003 if (p >= pvStart && p < pvEnd) { 1004 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1005 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1006 if (dof) { 1007 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1008 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1009 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1010 } 1011 } 1012 if (cdmCell && p >= pcStart && p < pcEnd) { 1013 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1014 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1015 if (dof) { 1016 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1017 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1018 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1019 } 1020 } 1021 } 1022 PetscCall(PetscViewerFlush(viewer)); 1023 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1024 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1025 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1026 } 1027 PetscCall(DMGetNumLabels(dm, &numLabels)); 1028 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1029 for (l = 0; l < numLabels; ++l) { 1030 DMLabel label; 1031 PetscBool isdepth; 1032 const char *name; 1033 1034 PetscCall(DMGetLabelName(dm, l, &name)); 1035 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1036 if (isdepth) continue; 1037 PetscCall(DMGetLabel(dm, name, &label)); 1038 PetscCall(DMLabelView(label, viewer)); 1039 } 1040 if (size > 1) { 1041 PetscSF sf; 1042 1043 PetscCall(DMGetPointSF(dm, &sf)); 1044 PetscCall(PetscSFView(sf, viewer)); 1045 } 1046 if (mesh->periodic.face_sfs) 1047 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 n = 4; 1088 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1089 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1091 if (!useLabels) numLabels = 0; 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1093 if (!useColors) { 1094 numColors = 3; 1095 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1096 } 1097 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1098 if (!useColors) { 1099 numLColors = 4; 1100 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1101 } 1102 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1103 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1104 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1105 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1106 if (depth < dim) plotEdges = PETSC_FALSE; 1107 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1108 1109 /* filter points with labelvalue != labeldefaultvalue */ 1110 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1112 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1114 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1115 if (lflg) { 1116 DMLabel lbl; 1117 1118 PetscCall(DMGetLabel(dm, lname, &lbl)); 1119 if (lbl) { 1120 PetscInt val, defval; 1121 1122 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1123 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1124 for (c = pStart; c < pEnd; c++) { 1125 PetscInt *closure = NULL; 1126 PetscInt closureSize; 1127 1128 PetscCall(DMLabelGetValue(lbl, c, &val)); 1129 if (val == defval) continue; 1130 1131 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1132 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1133 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 } 1135 } 1136 } 1137 1138 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1139 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1140 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1141 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1142 \\documentclass[tikz]{standalone}\n\n\ 1143 \\usepackage{pgflibraryshapes}\n\ 1144 \\usetikzlibrary{backgrounds}\n\ 1145 \\usetikzlibrary{arrows}\n\ 1146 \\begin{document}\n")); 1147 if (size > 1) { 1148 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1149 for (p = 0; p < size; ++p) { 1150 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1151 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1152 } 1153 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1154 } 1155 if (drawHasse) { 1156 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1157 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1171 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1172 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1173 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1174 } 1175 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1176 1177 /* Plot vertices */ 1178 PetscCall(VecGetArray(coordinates, &coords)); 1179 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1180 for (v = vStart; v < vEnd; ++v) { 1181 PetscInt off, dof, d; 1182 PetscBool isLabeled = PETSC_FALSE; 1183 1184 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1185 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1186 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1187 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1188 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1189 for (d = 0; d < dof; ++d) { 1190 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1191 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1192 } 1193 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1194 if (dim == 3) { 1195 PetscReal tmp = tcoords[1]; 1196 tcoords[1] = tcoords[2]; 1197 tcoords[2] = -tmp; 1198 } 1199 for (d = 0; d < dof; ++d) { 1200 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1201 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1202 } 1203 if (drawHasse) color = colors[0 % numColors]; 1204 else color = colors[rank % numColors]; 1205 for (l = 0; l < numLabels; ++l) { 1206 PetscInt val; 1207 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1208 if (val >= 0) { 1209 color = lcolors[l % numLColors]; 1210 isLabeled = PETSC_TRUE; 1211 break; 1212 } 1213 } 1214 if (drawNumbers[0]) { 1215 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1216 } else if (drawColors[0]) { 1217 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1218 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1219 } 1220 PetscCall(VecRestoreArray(coordinates, &coords)); 1221 PetscCall(PetscViewerFlush(viewer)); 1222 /* Plot edges */ 1223 if (plotEdges) { 1224 PetscCall(VecGetArray(coordinates, &coords)); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1226 for (e = eStart; e < eEnd; ++e) { 1227 const PetscInt *cone; 1228 PetscInt coneSize, offA, offB, dof, d; 1229 1230 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1231 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1232 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1233 PetscCall(DMPlexGetCone(dm, e, &cone)); 1234 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1235 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1236 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1237 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1238 for (d = 0; d < dof; ++d) { 1239 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1240 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1241 } 1242 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1243 if (dim == 3) { 1244 PetscReal tmp = tcoords[1]; 1245 tcoords[1] = tcoords[2]; 1246 tcoords[2] = -tmp; 1247 } 1248 for (d = 0; d < dof; ++d) { 1249 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1250 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1251 } 1252 if (drawHasse) color = colors[1 % numColors]; 1253 else color = colors[rank % numColors]; 1254 for (l = 0; l < numLabels; ++l) { 1255 PetscInt val; 1256 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1257 if (val >= 0) { 1258 color = lcolors[l % numLColors]; 1259 break; 1260 } 1261 } 1262 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1263 } 1264 PetscCall(VecRestoreArray(coordinates, &coords)); 1265 PetscCall(PetscViewerFlush(viewer)); 1266 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1267 } 1268 /* Plot cells */ 1269 if (dim == 3 || !drawNumbers[1]) { 1270 for (e = eStart; e < eEnd; ++e) { 1271 const PetscInt *cone; 1272 1273 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1274 color = colors[rank % numColors]; 1275 for (l = 0; l < numLabels; ++l) { 1276 PetscInt val; 1277 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1278 if (val >= 0) { 1279 color = lcolors[l % numLColors]; 1280 break; 1281 } 1282 } 1283 PetscCall(DMPlexGetCone(dm, e, &cone)); 1284 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1285 } 1286 } else { 1287 DMPolytopeType ct; 1288 1289 /* Drawing a 2D polygon */ 1290 for (c = cStart; c < cEnd; ++c) { 1291 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1292 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1293 if (DMPolytopeTypeIsHybrid(ct)) { 1294 const PetscInt *cone; 1295 PetscInt coneSize, e; 1296 1297 PetscCall(DMPlexGetCone(dm, c, &cone)); 1298 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1299 for (e = 0; e < coneSize; ++e) { 1300 const PetscInt *econe; 1301 1302 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1303 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1304 } 1305 } else { 1306 PetscInt *closure = NULL; 1307 PetscInt closureSize, Nv = 0, v; 1308 1309 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1310 for (p = 0; p < closureSize * 2; p += 2) { 1311 const PetscInt point = closure[p]; 1312 1313 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1314 } 1315 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1316 for (v = 0; v <= Nv; ++v) { 1317 const PetscInt vertex = closure[v % Nv]; 1318 1319 if (v > 0) { 1320 if (plotEdges) { 1321 const PetscInt *edge; 1322 PetscInt endpoints[2], ne; 1323 1324 endpoints[0] = closure[v - 1]; 1325 endpoints[1] = vertex; 1326 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1327 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1328 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1329 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1330 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1331 } 1332 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1333 } 1334 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1335 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1336 } 1337 } 1338 } 1339 for (c = cStart; c < cEnd; ++c) { 1340 double ccoords[3] = {0.0, 0.0, 0.0}; 1341 PetscBool isLabeled = PETSC_FALSE; 1342 PetscScalar *cellCoords = NULL; 1343 const PetscScalar *array; 1344 PetscInt numCoords, cdim, d; 1345 PetscBool isDG; 1346 1347 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1348 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1349 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1350 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1351 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1352 for (p = 0; p < numCoords / cdim; ++p) { 1353 for (d = 0; d < cdim; ++d) { 1354 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1355 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1356 } 1357 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1358 if (cdim == 3) { 1359 PetscReal tmp = tcoords[1]; 1360 tcoords[1] = tcoords[2]; 1361 tcoords[2] = -tmp; 1362 } 1363 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1364 } 1365 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1366 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1367 for (d = 0; d < cdim; ++d) { 1368 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1369 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1370 } 1371 if (drawHasse) color = colors[depth % numColors]; 1372 else color = colors[rank % numColors]; 1373 for (l = 0; l < numLabels; ++l) { 1374 PetscInt val; 1375 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1376 if (val >= 0) { 1377 color = lcolors[l % numLColors]; 1378 isLabeled = PETSC_TRUE; 1379 break; 1380 } 1381 } 1382 if (drawNumbers[dim]) { 1383 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1384 } else if (drawColors[dim]) { 1385 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1386 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1387 } 1388 if (drawHasse) { 1389 int height = 0; 1390 1391 color = colors[depth % numColors]; 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1397 1398 if (depth > 2) { 1399 color = colors[1 % numColors]; 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1404 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1405 } 1406 1407 color = colors[1 % numColors]; 1408 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1409 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1410 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1411 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1412 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1413 1414 color = colors[0 % numColors]; 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1420 1421 for (p = pStart; p < pEnd; ++p) { 1422 const PetscInt *cone; 1423 PetscInt coneSize, cp; 1424 1425 PetscCall(DMPlexGetCone(dm, p, &cone)); 1426 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1427 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1428 } 1429 } 1430 PetscCall(PetscViewerFlush(viewer)); 1431 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1432 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1433 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1434 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1435 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1436 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1437 PetscCall(PetscFree3(names, colors, lcolors)); 1438 PetscCall(PetscBTDestroy(&wp)); 1439 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1440 Vec cown, acown; 1441 VecScatter sct; 1442 ISLocalToGlobalMapping g2l; 1443 IS gid, acis; 1444 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1445 MPI_Group ggroup, ngroup; 1446 PetscScalar *array, nid; 1447 const PetscInt *idxs; 1448 PetscInt *idxs2, *start, *adjacency, *work; 1449 PetscInt64 lm[3], gm[3]; 1450 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1451 PetscMPIInt d1, d2, rank; 1452 1453 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1454 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1455 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1456 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1457 #endif 1458 if (ncomm != MPI_COMM_NULL) { 1459 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1460 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1461 d1 = 0; 1462 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1463 nid = d2; 1464 PetscCallMPI(MPI_Group_free(&ggroup)); 1465 PetscCallMPI(MPI_Group_free(&ngroup)); 1466 PetscCallMPI(MPI_Comm_free(&ncomm)); 1467 } else nid = 0.0; 1468 1469 /* Get connectivity */ 1470 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1471 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1472 1473 /* filter overlapped local cells */ 1474 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1475 PetscCall(ISGetIndices(gid, &idxs)); 1476 PetscCall(ISGetLocalSize(gid, &cum)); 1477 PetscCall(PetscMalloc1(cum, &idxs2)); 1478 for (c = cStart, cum = 0; c < cEnd; c++) { 1479 if (idxs[c - cStart] < 0) continue; 1480 idxs2[cum++] = idxs[c - cStart]; 1481 } 1482 PetscCall(ISRestoreIndices(gid, &idxs)); 1483 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1484 PetscCall(ISDestroy(&gid)); 1485 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1486 1487 /* support for node-aware cell locality */ 1488 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1489 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1490 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1491 PetscCall(VecGetArray(cown, &array)); 1492 for (c = 0; c < numVertices; c++) array[c] = nid; 1493 PetscCall(VecRestoreArray(cown, &array)); 1494 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1495 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1496 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1497 PetscCall(ISDestroy(&acis)); 1498 PetscCall(VecScatterDestroy(&sct)); 1499 PetscCall(VecDestroy(&cown)); 1500 1501 /* compute edgeCut */ 1502 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1503 PetscCall(PetscMalloc1(cum, &work)); 1504 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1505 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1506 PetscCall(ISDestroy(&gid)); 1507 PetscCall(VecGetArray(acown, &array)); 1508 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1509 PetscInt totl; 1510 1511 totl = start[c + 1] - start[c]; 1512 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1513 for (i = 0; i < totl; i++) { 1514 if (work[i] < 0) { 1515 ect += 1; 1516 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1517 } 1518 } 1519 } 1520 PetscCall(PetscFree(work)); 1521 PetscCall(VecRestoreArray(acown, &array)); 1522 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1523 lm[1] = -numVertices; 1524 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1526 lm[0] = ect; /* edgeCut */ 1527 lm[1] = ectn; /* node-aware edgeCut */ 1528 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1529 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1530 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1531 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1532 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1533 #else 1534 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1535 #endif 1536 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1537 PetscCall(PetscFree(start)); 1538 PetscCall(PetscFree(adjacency)); 1539 PetscCall(VecDestroy(&acown)); 1540 } else { 1541 const char *name; 1542 PetscInt *sizes, *hybsizes, *ghostsizes; 1543 PetscInt locDepth, depth, cellHeight, dim, d; 1544 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1545 PetscInt numLabels, l, maxSize = 17; 1546 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1547 MPI_Comm comm; 1548 PetscMPIInt size, rank; 1549 1550 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1551 PetscCallMPI(MPI_Comm_size(comm, &size)); 1552 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1553 PetscCall(DMGetDimension(dm, &dim)); 1554 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1555 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1556 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1557 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1558 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1559 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1560 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1561 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1562 gcNum = gcEnd - gcStart; 1563 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1564 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1565 for (d = 0; d <= depth; d++) { 1566 PetscInt Nc[2] = {0, 0}, ict; 1567 1568 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1569 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1570 ict = ct0; 1571 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1572 ct0 = (DMPolytopeType)ict; 1573 for (p = pStart; p < pEnd; ++p) { 1574 DMPolytopeType ct; 1575 1576 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1577 if (ct == ct0) ++Nc[0]; 1578 else ++Nc[1]; 1579 } 1580 if (size < maxSize) { 1581 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1582 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1583 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1584 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1585 for (p = 0; p < size; ++p) { 1586 if (rank == 0) { 1587 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1588 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1589 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1590 } 1591 } 1592 } else { 1593 PetscInt locMinMax[2]; 1594 1595 locMinMax[0] = Nc[0] + Nc[1]; 1596 locMinMax[1] = Nc[0] + Nc[1]; 1597 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1598 locMinMax[0] = Nc[1]; 1599 locMinMax[1] = Nc[1]; 1600 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1601 if (d == depth) { 1602 locMinMax[0] = gcNum; 1603 locMinMax[1] = gcNum; 1604 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1605 } 1606 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1607 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1608 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1609 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1610 } 1611 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1612 } 1613 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1614 { 1615 const PetscReal *maxCell; 1616 const PetscReal *L; 1617 PetscBool localized; 1618 1619 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1620 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1621 if (L || localized) { 1622 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1623 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1624 if (L) { 1625 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1626 for (d = 0; d < dim; ++d) { 1627 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1628 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1629 } 1630 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1631 } 1632 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1633 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1634 } 1635 } 1636 PetscCall(DMGetNumLabels(dm, &numLabels)); 1637 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1638 for (l = 0; l < numLabels; ++l) { 1639 DMLabel label; 1640 const char *name; 1641 IS valueIS; 1642 const PetscInt *values; 1643 PetscInt numValues, v; 1644 1645 PetscCall(DMGetLabelName(dm, l, &name)); 1646 PetscCall(DMGetLabel(dm, name, &label)); 1647 PetscCall(DMLabelGetNumValues(label, &numValues)); 1648 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1649 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1650 PetscCall(ISGetIndices(valueIS, &values)); 1651 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1652 for (v = 0; v < numValues; ++v) { 1653 PetscInt size; 1654 1655 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1656 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1657 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1658 } 1659 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1660 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1661 PetscCall(ISRestoreIndices(valueIS, &values)); 1662 PetscCall(ISDestroy(&valueIS)); 1663 } 1664 { 1665 char **labelNames; 1666 PetscInt Nl = numLabels; 1667 PetscBool flg; 1668 1669 PetscCall(PetscMalloc1(Nl, &labelNames)); 1670 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1671 for (l = 0; l < Nl; ++l) { 1672 DMLabel label; 1673 1674 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1675 if (flg) { 1676 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1677 PetscCall(DMLabelView(label, viewer)); 1678 } 1679 PetscCall(PetscFree(labelNames[l])); 1680 } 1681 PetscCall(PetscFree(labelNames)); 1682 } 1683 /* If no fields are specified, people do not want to see adjacency */ 1684 if (dm->Nf) { 1685 PetscInt f; 1686 1687 for (f = 0; f < dm->Nf; ++f) { 1688 const char *name; 1689 1690 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1691 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1692 PetscCall(PetscViewerASCIIPushTab(viewer)); 1693 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1694 if (dm->fields[f].adjacency[0]) { 1695 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1696 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1697 } else { 1698 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1699 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1700 } 1701 PetscCall(PetscViewerASCIIPopTab(viewer)); 1702 } 1703 } 1704 PetscCall(DMGetCoarseDM(dm, &cdm)); 1705 if (cdm) { 1706 PetscCall(PetscViewerASCIIPushTab(viewer)); 1707 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1708 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1709 PetscCall(PetscViewerASCIIPopTab(viewer)); 1710 } 1711 } 1712 PetscFunctionReturn(PETSC_SUCCESS); 1713 } 1714 1715 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1716 { 1717 DMPolytopeType ct; 1718 PetscMPIInt rank; 1719 PetscInt cdim; 1720 1721 PetscFunctionBegin; 1722 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1723 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1724 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1725 switch (ct) { 1726 case DM_POLYTOPE_SEGMENT: 1727 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1728 switch (cdim) { 1729 case 1: { 1730 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1731 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1732 1733 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1734 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1735 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1736 } break; 1737 case 2: { 1738 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1739 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1740 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1741 1742 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1745 } break; 1746 default: 1747 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1748 } 1749 break; 1750 case DM_POLYTOPE_TRIANGLE: 1751 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1755 break; 1756 case DM_POLYTOPE_QUADRILATERAL: 1757 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1758 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1759 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1760 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1761 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1762 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1763 break; 1764 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1765 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1766 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1767 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1768 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1769 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1770 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1771 break; 1772 case DM_POLYTOPE_FV_GHOST: 1773 break; 1774 default: 1775 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1776 } 1777 PetscFunctionReturn(PETSC_SUCCESS); 1778 } 1779 1780 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1781 { 1782 PetscReal centroid[2] = {0., 0.}; 1783 PetscMPIInt rank; 1784 PetscInt fillColor; 1785 1786 PetscFunctionBegin; 1787 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1788 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1789 for (PetscInt v = 0; v < Nv; ++v) { 1790 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1791 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1792 } 1793 for (PetscInt e = 0; e < Nv; ++e) { 1794 refCoords[0] = refVertices[e * 2 + 0]; 1795 refCoords[1] = refVertices[e * 2 + 1]; 1796 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1797 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1798 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1799 } 1800 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1801 for (PetscInt d = 0; d < edgeDiv; ++d) { 1802 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1803 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1804 } 1805 } 1806 PetscFunctionReturn(PETSC_SUCCESS); 1807 } 1808 1809 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1810 { 1811 DMPolytopeType ct; 1812 1813 PetscFunctionBegin; 1814 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1815 switch (ct) { 1816 case DM_POLYTOPE_TRIANGLE: { 1817 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1818 1819 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1820 } break; 1821 case DM_POLYTOPE_QUADRILATERAL: { 1822 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1823 1824 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1825 } break; 1826 default: 1827 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1828 } 1829 PetscFunctionReturn(PETSC_SUCCESS); 1830 } 1831 1832 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1833 { 1834 PetscDraw draw; 1835 DM cdm; 1836 PetscSection coordSection; 1837 Vec coordinates; 1838 PetscReal xyl[3], xyr[3]; 1839 PetscReal *refCoords, *edgeCoords; 1840 PetscBool isnull, drawAffine; 1841 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1842 1843 PetscFunctionBegin; 1844 PetscCall(DMGetCoordinateDim(dm, &dim)); 1845 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1846 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1847 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1848 edgeDiv = cDegree + 1; 1849 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1850 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1851 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1852 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1853 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1854 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1855 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1856 1857 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1858 PetscCall(PetscDrawIsNull(draw, &isnull)); 1859 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1860 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1861 1862 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1863 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1864 PetscCall(PetscDrawClear(draw)); 1865 1866 for (c = cStart; c < cEnd; ++c) { 1867 PetscScalar *coords = NULL; 1868 const PetscScalar *coords_arr; 1869 PetscInt numCoords; 1870 PetscBool isDG; 1871 1872 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1873 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1874 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1875 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1876 } 1877 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1878 PetscCall(PetscDrawFlush(draw)); 1879 PetscCall(PetscDrawPause(draw)); 1880 PetscCall(PetscDrawSave(draw)); 1881 PetscFunctionReturn(PETSC_SUCCESS); 1882 } 1883 1884 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1885 { 1886 DM odm = dm, rdm = dm, cdm; 1887 PetscFE fe; 1888 PetscSpace sp; 1889 PetscClassId id; 1890 PetscInt degree; 1891 PetscBool hoView = PETSC_TRUE; 1892 1893 PetscFunctionBegin; 1894 PetscObjectOptionsBegin((PetscObject)dm); 1895 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1896 PetscOptionsEnd(); 1897 PetscCall(PetscObjectReference((PetscObject)dm)); 1898 *hdm = dm; 1899 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1900 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1901 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1902 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1903 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1904 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1905 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1906 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1907 DM cdm, rcdm; 1908 Mat In; 1909 Vec cl, rcl; 1910 1911 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1912 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1913 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1914 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1915 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1916 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1917 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1918 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1919 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1920 PetscCall(MatMult(In, cl, rcl)); 1921 PetscCall(MatDestroy(&In)); 1922 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1923 PetscCall(DMDestroy(&odm)); 1924 odm = rdm; 1925 } 1926 *hdm = rdm; 1927 PetscFunctionReturn(PETSC_SUCCESS); 1928 } 1929 1930 #if defined(PETSC_HAVE_EXODUSII) 1931 #include <exodusII.h> 1932 #include <petscviewerexodusii.h> 1933 #endif 1934 1935 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1936 { 1937 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1938 char name[PETSC_MAX_PATH_LEN]; 1939 1940 PetscFunctionBegin; 1941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1942 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1943 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1944 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1945 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1946 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1947 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1948 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1949 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1950 if (iascii) { 1951 PetscViewerFormat format; 1952 PetscCall(PetscViewerGetFormat(viewer, &format)); 1953 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1954 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1955 } else if (ishdf5) { 1956 #if defined(PETSC_HAVE_HDF5) 1957 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1958 #else 1959 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1960 #endif 1961 } else if (isvtk) { 1962 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1963 } else if (isdraw) { 1964 DM hdm; 1965 1966 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1967 PetscCall(DMPlexView_Draw(hdm, viewer)); 1968 PetscCall(DMDestroy(&hdm)); 1969 } else if (isglvis) { 1970 PetscCall(DMPlexView_GLVis(dm, viewer)); 1971 #if defined(PETSC_HAVE_EXODUSII) 1972 } else if (isexodus) { 1973 /* 1974 exodusII requires that all sets be part of exactly one cell set. 1975 If the dm does not have a "Cell Sets" label defined, we create one 1976 with ID 1, containing all cells. 1977 Note that if the Cell Sets label is defined but does not cover all cells, 1978 we may still have a problem. This should probably be checked here or in the viewer; 1979 */ 1980 PetscInt numCS; 1981 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1982 if (!numCS) { 1983 PetscInt cStart, cEnd, c; 1984 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1985 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1986 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1987 } 1988 PetscCall(DMView_PlexExodusII(dm, viewer)); 1989 #endif 1990 #if defined(PETSC_HAVE_CGNS) 1991 } else if (iscgns) { 1992 PetscCall(DMView_PlexCGNS(dm, viewer)); 1993 #endif 1994 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1995 /* Optionally view the partition */ 1996 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1997 if (flg) { 1998 Vec ranks; 1999 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2000 PetscCall(VecView(ranks, viewer)); 2001 PetscCall(VecDestroy(&ranks)); 2002 } 2003 /* Optionally view a label */ 2004 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2005 if (flg) { 2006 DMLabel label; 2007 Vec val; 2008 2009 PetscCall(DMGetLabel(dm, name, &label)); 2010 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2011 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2012 PetscCall(VecView(val, viewer)); 2013 PetscCall(VecDestroy(&val)); 2014 } 2015 PetscFunctionReturn(PETSC_SUCCESS); 2016 } 2017 2018 /*@ 2019 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2020 2021 Collective 2022 2023 Input Parameters: 2024 + dm - The `DM` whose topology is to be saved 2025 - viewer - The `PetscViewer` to save it in 2026 2027 Level: advanced 2028 2029 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2030 @*/ 2031 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2032 { 2033 PetscBool ishdf5; 2034 2035 PetscFunctionBegin; 2036 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2037 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2038 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2039 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2040 if (ishdf5) { 2041 #if defined(PETSC_HAVE_HDF5) 2042 PetscViewerFormat format; 2043 PetscCall(PetscViewerGetFormat(viewer, &format)); 2044 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2045 IS globalPointNumbering; 2046 2047 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2048 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2049 PetscCall(ISDestroy(&globalPointNumbering)); 2050 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2051 #else 2052 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2053 #endif 2054 } 2055 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2056 PetscFunctionReturn(PETSC_SUCCESS); 2057 } 2058 2059 /*@ 2060 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2061 2062 Collective 2063 2064 Input Parameters: 2065 + dm - The `DM` whose coordinates are to be saved 2066 - viewer - The `PetscViewer` for saving 2067 2068 Level: advanced 2069 2070 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2071 @*/ 2072 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2073 { 2074 PetscBool ishdf5; 2075 2076 PetscFunctionBegin; 2077 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2078 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2079 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2080 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2081 if (ishdf5) { 2082 #if defined(PETSC_HAVE_HDF5) 2083 PetscViewerFormat format; 2084 PetscCall(PetscViewerGetFormat(viewer, &format)); 2085 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2086 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2087 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2088 #else 2089 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2090 #endif 2091 } 2092 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2093 PetscFunctionReturn(PETSC_SUCCESS); 2094 } 2095 2096 /*@ 2097 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2098 2099 Collective 2100 2101 Input Parameters: 2102 + dm - The `DM` whose labels are to be saved 2103 - viewer - The `PetscViewer` for saving 2104 2105 Level: advanced 2106 2107 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2108 @*/ 2109 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2110 { 2111 PetscBool ishdf5; 2112 2113 PetscFunctionBegin; 2114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2115 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2116 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2117 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2118 if (ishdf5) { 2119 #if defined(PETSC_HAVE_HDF5) 2120 IS globalPointNumbering; 2121 PetscViewerFormat format; 2122 2123 PetscCall(PetscViewerGetFormat(viewer, &format)); 2124 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2125 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2126 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2127 PetscCall(ISDestroy(&globalPointNumbering)); 2128 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2129 #else 2130 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2131 #endif 2132 } 2133 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2134 PetscFunctionReturn(PETSC_SUCCESS); 2135 } 2136 2137 /*@ 2138 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2139 2140 Collective 2141 2142 Input Parameters: 2143 + dm - The `DM` that contains the topology on which the section to be saved is defined 2144 . viewer - The `PetscViewer` for saving 2145 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2146 2147 Level: advanced 2148 2149 Notes: 2150 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 2151 2152 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2153 2154 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2155 @*/ 2156 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2157 { 2158 PetscBool ishdf5; 2159 2160 PetscFunctionBegin; 2161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2162 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2163 if (!sectiondm) sectiondm = dm; 2164 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2165 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2166 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2167 if (ishdf5) { 2168 #if defined(PETSC_HAVE_HDF5) 2169 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2170 #else 2171 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2172 #endif 2173 } 2174 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2175 PetscFunctionReturn(PETSC_SUCCESS); 2176 } 2177 2178 /*@ 2179 DMPlexGlobalVectorView - Saves a global vector 2180 2181 Collective 2182 2183 Input Parameters: 2184 + dm - The `DM` that represents the topology 2185 . viewer - The `PetscViewer` to save data with 2186 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2187 - vec - The global vector to be saved 2188 2189 Level: advanced 2190 2191 Notes: 2192 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2193 2194 Calling sequence: 2195 .vb 2196 DMCreate(PETSC_COMM_WORLD, &dm); 2197 DMSetType(dm, DMPLEX); 2198 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2199 DMClone(dm, §iondm); 2200 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2201 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2202 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2203 PetscSectionSetChart(section, pStart, pEnd); 2204 PetscSectionSetUp(section); 2205 DMSetLocalSection(sectiondm, section); 2206 PetscSectionDestroy(§ion); 2207 DMGetGlobalVector(sectiondm, &vec); 2208 PetscObjectSetName((PetscObject)vec, "vec_name"); 2209 DMPlexTopologyView(dm, viewer); 2210 DMPlexSectionView(dm, viewer, sectiondm); 2211 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2212 DMRestoreGlobalVector(sectiondm, &vec); 2213 DMDestroy(§iondm); 2214 DMDestroy(&dm); 2215 .ve 2216 2217 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2218 @*/ 2219 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2220 { 2221 PetscBool ishdf5; 2222 2223 PetscFunctionBegin; 2224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2225 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2226 if (!sectiondm) sectiondm = dm; 2227 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2228 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2229 /* Check consistency */ 2230 { 2231 PetscSection section; 2232 PetscBool includesConstraints; 2233 PetscInt m, m1; 2234 2235 PetscCall(VecGetLocalSize(vec, &m1)); 2236 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2237 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2238 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2239 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2240 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2241 } 2242 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2243 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2244 if (ishdf5) { 2245 #if defined(PETSC_HAVE_HDF5) 2246 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2247 #else 2248 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2249 #endif 2250 } 2251 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2252 PetscFunctionReturn(PETSC_SUCCESS); 2253 } 2254 2255 /*@ 2256 DMPlexLocalVectorView - Saves a local vector 2257 2258 Collective 2259 2260 Input Parameters: 2261 + dm - The `DM` that represents the topology 2262 . viewer - The `PetscViewer` to save data with 2263 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2264 - vec - The local vector to be saved 2265 2266 Level: advanced 2267 2268 Note: 2269 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2270 2271 Calling sequence: 2272 .vb 2273 DMCreate(PETSC_COMM_WORLD, &dm); 2274 DMSetType(dm, DMPLEX); 2275 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2276 DMClone(dm, §iondm); 2277 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2278 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2279 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2280 PetscSectionSetChart(section, pStart, pEnd); 2281 PetscSectionSetUp(section); 2282 DMSetLocalSection(sectiondm, section); 2283 DMGetLocalVector(sectiondm, &vec); 2284 PetscObjectSetName((PetscObject)vec, "vec_name"); 2285 DMPlexTopologyView(dm, viewer); 2286 DMPlexSectionView(dm, viewer, sectiondm); 2287 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2288 DMRestoreLocalVector(sectiondm, &vec); 2289 DMDestroy(§iondm); 2290 DMDestroy(&dm); 2291 .ve 2292 2293 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2294 @*/ 2295 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2296 { 2297 PetscBool ishdf5; 2298 2299 PetscFunctionBegin; 2300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2301 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2302 if (!sectiondm) sectiondm = dm; 2303 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2304 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2305 /* Check consistency */ 2306 { 2307 PetscSection section; 2308 PetscBool includesConstraints; 2309 PetscInt m, m1; 2310 2311 PetscCall(VecGetLocalSize(vec, &m1)); 2312 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2313 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2314 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2315 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2316 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2317 } 2318 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2319 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2320 if (ishdf5) { 2321 #if defined(PETSC_HAVE_HDF5) 2322 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2323 #else 2324 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2325 #endif 2326 } 2327 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2328 PetscFunctionReturn(PETSC_SUCCESS); 2329 } 2330 2331 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2332 { 2333 PetscBool ishdf5; 2334 2335 PetscFunctionBegin; 2336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2337 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2338 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2339 if (ishdf5) { 2340 #if defined(PETSC_HAVE_HDF5) 2341 PetscViewerFormat format; 2342 PetscCall(PetscViewerGetFormat(viewer, &format)); 2343 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2344 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2345 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2346 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2347 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2348 PetscFunctionReturn(PETSC_SUCCESS); 2349 #else 2350 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2351 #endif 2352 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2353 } 2354 2355 /*@ 2356 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2357 2358 Collective 2359 2360 Input Parameters: 2361 + dm - The `DM` into which the topology is loaded 2362 - viewer - The `PetscViewer` for the saved topology 2363 2364 Output Parameter: 2365 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded 2366 2367 Level: advanced 2368 2369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2370 `PetscViewer`, `PetscSF` 2371 @*/ 2372 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2373 { 2374 PetscBool ishdf5; 2375 2376 PetscFunctionBegin; 2377 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2378 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2379 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2380 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2381 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2382 if (ishdf5) { 2383 #if defined(PETSC_HAVE_HDF5) 2384 PetscViewerFormat format; 2385 PetscCall(PetscViewerGetFormat(viewer, &format)); 2386 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2387 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2388 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2389 #else 2390 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2391 #endif 2392 } 2393 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2394 PetscFunctionReturn(PETSC_SUCCESS); 2395 } 2396 2397 /*@ 2398 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2399 2400 Collective 2401 2402 Input Parameters: 2403 + dm - The `DM` into which the coordinates are loaded 2404 . viewer - The `PetscViewer` for the saved coordinates 2405 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2406 2407 Level: advanced 2408 2409 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2410 `PetscSF`, `PetscViewer` 2411 @*/ 2412 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2413 { 2414 PetscBool ishdf5; 2415 2416 PetscFunctionBegin; 2417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2418 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2419 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2420 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2421 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2422 if (ishdf5) { 2423 #if defined(PETSC_HAVE_HDF5) 2424 PetscViewerFormat format; 2425 PetscCall(PetscViewerGetFormat(viewer, &format)); 2426 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2427 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2428 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2429 #else 2430 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2431 #endif 2432 } 2433 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2434 PetscFunctionReturn(PETSC_SUCCESS); 2435 } 2436 2437 /*@ 2438 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2439 2440 Collective 2441 2442 Input Parameters: 2443 + dm - The `DM` into which the labels are loaded 2444 . viewer - The `PetscViewer` for the saved labels 2445 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2446 2447 Level: advanced 2448 2449 Note: 2450 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2451 2452 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2453 `PetscSF`, `PetscViewer` 2454 @*/ 2455 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2456 { 2457 PetscBool ishdf5; 2458 2459 PetscFunctionBegin; 2460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2461 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2462 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2463 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2464 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2465 if (ishdf5) { 2466 #if defined(PETSC_HAVE_HDF5) 2467 PetscViewerFormat format; 2468 2469 PetscCall(PetscViewerGetFormat(viewer, &format)); 2470 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2471 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2472 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2473 #else 2474 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2475 #endif 2476 } 2477 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2478 PetscFunctionReturn(PETSC_SUCCESS); 2479 } 2480 2481 /*@ 2482 DMPlexSectionLoad - Loads section into a `DMPLEX` 2483 2484 Collective 2485 2486 Input Parameters: 2487 + dm - The `DM` that represents the topology 2488 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2489 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2490 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2491 2492 Output Parameters: 2493 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2494 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2495 2496 Level: advanced 2497 2498 Notes: 2499 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2500 2501 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2502 2503 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2504 2505 Example using 2 processes: 2506 .vb 2507 NX (number of points on dm): 4 2508 sectionA : the on-disk section 2509 vecA : a vector associated with sectionA 2510 sectionB : sectiondm's local section constructed in this function 2511 vecB (local) : a vector associated with sectiondm's local section 2512 vecB (global) : a vector associated with sectiondm's global section 2513 2514 rank 0 rank 1 2515 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2516 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2517 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2518 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2519 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2520 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2521 sectionB->atlasDof : 1 0 1 | 1 3 2522 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2523 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2524 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2525 .ve 2526 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2527 2528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2529 @*/ 2530 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2531 { 2532 PetscBool ishdf5; 2533 2534 PetscFunctionBegin; 2535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2536 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2537 if (!sectiondm) sectiondm = dm; 2538 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2539 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2540 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2541 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2542 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2543 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2544 if (ishdf5) { 2545 #if defined(PETSC_HAVE_HDF5) 2546 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2547 #else 2548 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2549 #endif 2550 } 2551 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2552 PetscFunctionReturn(PETSC_SUCCESS); 2553 } 2554 2555 /*@ 2556 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2557 2558 Collective 2559 2560 Input Parameters: 2561 + dm - The `DM` that represents the topology 2562 . viewer - The `PetscViewer` that represents the on-disk vector data 2563 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2564 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2565 - vec - The global vector to set values of 2566 2567 Level: advanced 2568 2569 Notes: 2570 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2571 2572 Calling sequence: 2573 .vb 2574 DMCreate(PETSC_COMM_WORLD, &dm); 2575 DMSetType(dm, DMPLEX); 2576 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2577 DMPlexTopologyLoad(dm, viewer, &sfX); 2578 DMClone(dm, §iondm); 2579 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2580 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2581 DMGetGlobalVector(sectiondm, &vec); 2582 PetscObjectSetName((PetscObject)vec, "vec_name"); 2583 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2584 DMRestoreGlobalVector(sectiondm, &vec); 2585 PetscSFDestroy(&gsf); 2586 PetscSFDestroy(&sfX); 2587 DMDestroy(§iondm); 2588 DMDestroy(&dm); 2589 .ve 2590 2591 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2592 `PetscSF`, `PetscViewer` 2593 @*/ 2594 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2595 { 2596 PetscBool ishdf5; 2597 2598 PetscFunctionBegin; 2599 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2600 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2601 if (!sectiondm) sectiondm = dm; 2602 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2603 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2604 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2605 /* Check consistency */ 2606 { 2607 PetscSection section; 2608 PetscBool includesConstraints; 2609 PetscInt m, m1; 2610 2611 PetscCall(VecGetLocalSize(vec, &m1)); 2612 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2613 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2614 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2615 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2616 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2617 } 2618 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2619 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2620 if (ishdf5) { 2621 #if defined(PETSC_HAVE_HDF5) 2622 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2623 #else 2624 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2625 #endif 2626 } 2627 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2628 PetscFunctionReturn(PETSC_SUCCESS); 2629 } 2630 2631 /*@ 2632 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2633 2634 Collective 2635 2636 Input Parameters: 2637 + dm - The `DM` that represents the topology 2638 . viewer - The `PetscViewer` that represents the on-disk vector data 2639 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2640 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2641 - vec - The local vector to set values of 2642 2643 Level: advanced 2644 2645 Notes: 2646 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2647 2648 Calling sequence: 2649 .vb 2650 DMCreate(PETSC_COMM_WORLD, &dm); 2651 DMSetType(dm, DMPLEX); 2652 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2653 DMPlexTopologyLoad(dm, viewer, &sfX); 2654 DMClone(dm, §iondm); 2655 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2656 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2657 DMGetLocalVector(sectiondm, &vec); 2658 PetscObjectSetName((PetscObject)vec, "vec_name"); 2659 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2660 DMRestoreLocalVector(sectiondm, &vec); 2661 PetscSFDestroy(&lsf); 2662 PetscSFDestroy(&sfX); 2663 DMDestroy(§iondm); 2664 DMDestroy(&dm); 2665 .ve 2666 2667 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2668 `PetscSF`, `PetscViewer` 2669 @*/ 2670 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2671 { 2672 PetscBool ishdf5; 2673 2674 PetscFunctionBegin; 2675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2676 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2677 if (!sectiondm) sectiondm = dm; 2678 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2679 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2680 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2681 /* Check consistency */ 2682 { 2683 PetscSection section; 2684 PetscBool includesConstraints; 2685 PetscInt m, m1; 2686 2687 PetscCall(VecGetLocalSize(vec, &m1)); 2688 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2689 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2690 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2691 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2692 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2693 } 2694 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2695 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2696 if (ishdf5) { 2697 #if defined(PETSC_HAVE_HDF5) 2698 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2699 #else 2700 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2701 #endif 2702 } 2703 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2704 PetscFunctionReturn(PETSC_SUCCESS); 2705 } 2706 2707 PetscErrorCode DMDestroy_Plex(DM dm) 2708 { 2709 DM_Plex *mesh = (DM_Plex *)dm->data; 2710 2711 PetscFunctionBegin; 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2714 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2716 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2717 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2718 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2719 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2720 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2721 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2722 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2723 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2724 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2725 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2726 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2727 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2728 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2729 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2730 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2731 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2732 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2733 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2734 PetscCall(PetscFree(mesh->cones)); 2735 PetscCall(PetscFree(mesh->coneOrientations)); 2736 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2737 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2738 PetscCall(PetscFree(mesh->supports)); 2739 PetscCall(PetscFree(mesh->cellTypes)); 2740 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2741 PetscCall(PetscFree(mesh->tetgenOpts)); 2742 PetscCall(PetscFree(mesh->triangleOpts)); 2743 PetscCall(PetscFree(mesh->transformType)); 2744 PetscCall(PetscFree(mesh->distributionName)); 2745 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2746 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2747 PetscCall(ISDestroy(&mesh->subpointIS)); 2748 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2749 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2750 if (mesh->periodic.face_sfs) { 2751 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2752 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2753 } 2754 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2755 if (mesh->periodic.periodic_points) { 2756 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2757 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2758 } 2759 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2760 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2761 PetscCall(ISDestroy(&mesh->anchorIS)); 2762 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2763 PetscCall(PetscFree(mesh->parents)); 2764 PetscCall(PetscFree(mesh->childIDs)); 2765 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2766 PetscCall(PetscFree(mesh->children)); 2767 PetscCall(DMDestroy(&mesh->referenceTree)); 2768 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2769 PetscCall(PetscFree(mesh->neighbors)); 2770 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2771 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2772 PetscCall(PetscFree(mesh)); 2773 PetscFunctionReturn(PETSC_SUCCESS); 2774 } 2775 2776 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2777 { 2778 PetscSection sectionGlobal, sectionLocal; 2779 PetscInt bs = -1, mbs; 2780 PetscInt localSize, localStart = 0; 2781 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2782 MatType mtype; 2783 ISLocalToGlobalMapping ltog; 2784 2785 PetscFunctionBegin; 2786 PetscCall(MatInitializePackage()); 2787 mtype = dm->mattype; 2788 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2789 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2790 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2791 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2792 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2793 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2794 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2795 PetscCall(MatSetType(*J, mtype)); 2796 PetscCall(MatSetFromOptions(*J)); 2797 PetscCall(MatGetBlockSize(*J, &mbs)); 2798 if (mbs > 1) bs = mbs; 2799 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2800 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2801 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2802 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2803 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2804 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2805 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2806 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2807 if (!isShell) { 2808 // There are three states with pblocks, since block starts can have no dofs: 2809 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2810 // TRUE) Block Start: The first entry in a block has been added 2811 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2812 PetscBT blst; 2813 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2814 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2815 const PetscInt *perm = NULL; 2816 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2817 PetscInt pStart, pEnd, dof, cdof, num_fields; 2818 2819 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2820 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2821 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2822 2823 PetscCall(PetscCalloc1(localSize, &pblocks)); 2824 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2825 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2826 // We need to process in the permuted order to get block sizes right 2827 for (PetscInt point = pStart; point < pEnd; ++point) { 2828 const PetscInt p = perm ? perm[point] : point; 2829 2830 switch (dm->blocking_type) { 2831 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2832 PetscInt bdof, offset; 2833 2834 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2835 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2836 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2837 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2838 if (dof > 0) { 2839 // State change 2840 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2841 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2842 2843 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2844 // Signal block concatenation 2845 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2846 } 2847 dof = dof < 0 ? -(dof + 1) : dof; 2848 bdof = cdof && (dof - cdof) ? 1 : dof; 2849 if (dof) { 2850 if (bs < 0) { 2851 bs = bdof; 2852 } else if (bs != bdof) { 2853 bs = 1; 2854 } 2855 } 2856 } break; 2857 case DM_BLOCKING_FIELD_NODE: { 2858 for (PetscInt field = 0; field < num_fields; field++) { 2859 PetscInt num_comp, bdof, offset; 2860 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2861 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2862 if (dof < 0) continue; 2863 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2864 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2865 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2866 PetscInt num_nodes = dof / num_comp; 2867 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2868 // Handle possibly constant block size (unlikely) 2869 bdof = cdof && (dof - cdof) ? 1 : dof; 2870 if (dof) { 2871 if (bs < 0) { 2872 bs = bdof; 2873 } else if (bs != bdof) { 2874 bs = 1; 2875 } 2876 } 2877 } 2878 } break; 2879 } 2880 } 2881 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2882 /* Must have same blocksize on all procs (some might have no points) */ 2883 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2884 bsLocal[1] = bs; 2885 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2886 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2887 else bs = bsMinMax[0]; 2888 bs = PetscMax(1, bs); 2889 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2890 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2891 PetscCall(MatSetBlockSize(*J, bs)); 2892 PetscCall(MatSetUp(*J)); 2893 } else { 2894 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2895 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2896 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2897 } 2898 if (pblocks) { // Consolidate blocks 2899 PetscInt nblocks = 0; 2900 pblocks[0] = PetscAbs(pblocks[0]); 2901 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2902 if (pblocks[i] == 0) continue; 2903 // Negative block size indicates the blocks should be concatenated 2904 if (pblocks[i] < 0) { 2905 pblocks[i] = -pblocks[i]; 2906 pblocks[nblocks - 1] += pblocks[i]; 2907 } else { 2908 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2909 } 2910 for (PetscInt j = 1; j < pblocks[i]; j++) 2911 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 2912 } 2913 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2914 } 2915 PetscCall(PetscFree(pblocks)); 2916 } 2917 PetscCall(MatSetDM(*J, dm)); 2918 PetscFunctionReturn(PETSC_SUCCESS); 2919 } 2920 2921 /*@ 2922 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2923 2924 Not Collective 2925 2926 Input Parameter: 2927 . dm - The `DMPLEX` 2928 2929 Output Parameter: 2930 . subsection - The subdomain section 2931 2932 Level: developer 2933 2934 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2935 @*/ 2936 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2937 { 2938 DM_Plex *mesh = (DM_Plex *)dm->data; 2939 2940 PetscFunctionBegin; 2941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2942 if (!mesh->subdomainSection) { 2943 PetscSection section; 2944 PetscSF sf; 2945 2946 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2947 PetscCall(DMGetLocalSection(dm, §ion)); 2948 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2949 PetscCall(PetscSFDestroy(&sf)); 2950 } 2951 *subsection = mesh->subdomainSection; 2952 PetscFunctionReturn(PETSC_SUCCESS); 2953 } 2954 2955 /*@ 2956 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2957 2958 Not Collective 2959 2960 Input Parameter: 2961 . dm - The `DMPLEX` 2962 2963 Output Parameters: 2964 + pStart - The first mesh point 2965 - pEnd - The upper bound for mesh points 2966 2967 Level: beginner 2968 2969 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2970 @*/ 2971 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2972 { 2973 DM_Plex *mesh = (DM_Plex *)dm->data; 2974 2975 PetscFunctionBegin; 2976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2977 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2978 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2979 PetscFunctionReturn(PETSC_SUCCESS); 2980 } 2981 2982 /*@ 2983 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2984 2985 Not Collective 2986 2987 Input Parameters: 2988 + dm - The `DMPLEX` 2989 . pStart - The first mesh point 2990 - pEnd - The upper bound for mesh points 2991 2992 Level: beginner 2993 2994 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2995 @*/ 2996 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2997 { 2998 DM_Plex *mesh = (DM_Plex *)dm->data; 2999 3000 PetscFunctionBegin; 3001 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3002 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3003 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3004 PetscCall(PetscFree(mesh->cellTypes)); 3005 PetscFunctionReturn(PETSC_SUCCESS); 3006 } 3007 3008 /*@ 3009 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3010 3011 Not Collective 3012 3013 Input Parameters: 3014 + dm - The `DMPLEX` 3015 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3016 3017 Output Parameter: 3018 . size - The cone size for point `p` 3019 3020 Level: beginner 3021 3022 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3023 @*/ 3024 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3025 { 3026 DM_Plex *mesh = (DM_Plex *)dm->data; 3027 3028 PetscFunctionBegin; 3029 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3030 PetscAssertPointer(size, 3); 3031 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3032 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3033 PetscFunctionReturn(PETSC_SUCCESS); 3034 } 3035 3036 /*@ 3037 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3038 3039 Not Collective 3040 3041 Input Parameters: 3042 + dm - The `DMPLEX` 3043 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3044 - size - The cone size for point `p` 3045 3046 Level: beginner 3047 3048 Note: 3049 This should be called after `DMPlexSetChart()`. 3050 3051 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3052 @*/ 3053 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3054 { 3055 DM_Plex *mesh = (DM_Plex *)dm->data; 3056 3057 PetscFunctionBegin; 3058 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3059 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3060 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3061 PetscFunctionReturn(PETSC_SUCCESS); 3062 } 3063 3064 /*@C 3065 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3066 3067 Not Collective 3068 3069 Input Parameters: 3070 + dm - The `DMPLEX` 3071 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3072 3073 Output Parameter: 3074 . cone - An array of points which are on the in-edges for point `p` 3075 3076 Level: beginner 3077 3078 Fortran Notes: 3079 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3080 `DMPlexRestoreCone()` is not needed/available in C. 3081 3082 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3083 @*/ 3084 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3085 { 3086 DM_Plex *mesh = (DM_Plex *)dm->data; 3087 PetscInt off; 3088 3089 PetscFunctionBegin; 3090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3091 PetscAssertPointer(cone, 3); 3092 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3093 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3094 PetscFunctionReturn(PETSC_SUCCESS); 3095 } 3096 3097 /*@ 3098 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3099 3100 Not Collective 3101 3102 Input Parameters: 3103 + dm - The `DMPLEX` 3104 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3105 3106 Output Parameters: 3107 + pConesSection - `PetscSection` describing the layout of `pCones` 3108 - pCones - An array of points which are on the in-edges for the point set `p` 3109 3110 Level: intermediate 3111 3112 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3113 @*/ 3114 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3115 { 3116 PetscSection cs, newcs; 3117 PetscInt *cones; 3118 PetscInt *newarr = NULL; 3119 PetscInt n; 3120 3121 PetscFunctionBegin; 3122 PetscCall(DMPlexGetCones(dm, &cones)); 3123 PetscCall(DMPlexGetConeSection(dm, &cs)); 3124 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3125 if (pConesSection) *pConesSection = newcs; 3126 if (pCones) { 3127 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3128 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3129 } 3130 PetscFunctionReturn(PETSC_SUCCESS); 3131 } 3132 3133 /*@ 3134 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3135 3136 Not Collective 3137 3138 Input Parameters: 3139 + dm - The `DMPLEX` 3140 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3141 3142 Output Parameter: 3143 . expandedPoints - An array of vertices recursively expanded from input points 3144 3145 Level: advanced 3146 3147 Notes: 3148 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3149 3150 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3151 3152 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3153 `DMPlexGetDepth()`, `IS` 3154 @*/ 3155 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3156 { 3157 IS *expandedPointsAll; 3158 PetscInt depth; 3159 3160 PetscFunctionBegin; 3161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3162 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3163 PetscAssertPointer(expandedPoints, 3); 3164 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3165 *expandedPoints = expandedPointsAll[0]; 3166 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3167 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3168 PetscFunctionReturn(PETSC_SUCCESS); 3169 } 3170 3171 /*@ 3172 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 3173 3174 Not Collective 3175 3176 Input Parameters: 3177 + dm - The `DMPLEX` 3178 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3179 3180 Output Parameters: 3181 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3182 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3183 - sections - (optional) An array of sections which describe mappings from points to their cone points 3184 3185 Level: advanced 3186 3187 Notes: 3188 Like `DMPlexGetConeTuple()` but recursive. 3189 3190 Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 3191 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3192 3193 Array section has size equal to `depth`. Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\: 3194 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3195 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3196 3197 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3198 `DMPlexGetDepth()`, `PetscSection`, `IS` 3199 @*/ 3200 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3201 { 3202 const PetscInt *arr0 = NULL, *cone = NULL; 3203 PetscInt *arr = NULL, *newarr = NULL; 3204 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3205 IS *expandedPoints_; 3206 PetscSection *sections_; 3207 3208 PetscFunctionBegin; 3209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3210 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3211 if (depth) PetscAssertPointer(depth, 3); 3212 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3213 if (sections) PetscAssertPointer(sections, 5); 3214 PetscCall(ISGetLocalSize(points, &n)); 3215 PetscCall(ISGetIndices(points, &arr0)); 3216 PetscCall(DMPlexGetDepth(dm, &depth_)); 3217 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3218 PetscCall(PetscCalloc1(depth_, §ions_)); 3219 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3220 for (d = depth_ - 1; d >= 0; d--) { 3221 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3222 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3223 for (i = 0; i < n; i++) { 3224 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3225 if (arr[i] >= start && arr[i] < end) { 3226 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3227 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3228 } else { 3229 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3230 } 3231 } 3232 PetscCall(PetscSectionSetUp(sections_[d])); 3233 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3234 PetscCall(PetscMalloc1(newn, &newarr)); 3235 for (i = 0; i < n; i++) { 3236 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3237 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3238 if (cn > 1) { 3239 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3240 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3241 } else { 3242 newarr[co] = arr[i]; 3243 } 3244 } 3245 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3246 arr = newarr; 3247 n = newn; 3248 } 3249 PetscCall(ISRestoreIndices(points, &arr0)); 3250 *depth = depth_; 3251 if (expandedPoints) *expandedPoints = expandedPoints_; 3252 else { 3253 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3254 PetscCall(PetscFree(expandedPoints_)); 3255 } 3256 if (sections) *sections = sections_; 3257 else { 3258 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3259 PetscCall(PetscFree(sections_)); 3260 } 3261 PetscFunctionReturn(PETSC_SUCCESS); 3262 } 3263 3264 /*@ 3265 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3266 3267 Not Collective 3268 3269 Input Parameters: 3270 + dm - The `DMPLEX` 3271 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3272 3273 Output Parameters: 3274 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3275 . expandedPoints - (optional) An array of recursively expanded cones 3276 - sections - (optional) An array of sections which describe mappings from points to their cone points 3277 3278 Level: advanced 3279 3280 Note: 3281 See `DMPlexGetConeRecursive()` 3282 3283 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3284 `DMPlexGetDepth()`, `IS`, `PetscSection` 3285 @*/ 3286 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3287 { 3288 PetscInt d, depth_; 3289 3290 PetscFunctionBegin; 3291 PetscCall(DMPlexGetDepth(dm, &depth_)); 3292 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3293 if (depth) *depth = 0; 3294 if (expandedPoints) { 3295 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3296 PetscCall(PetscFree(*expandedPoints)); 3297 } 3298 if (sections) { 3299 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3300 PetscCall(PetscFree(*sections)); 3301 } 3302 PetscFunctionReturn(PETSC_SUCCESS); 3303 } 3304 3305 /*@ 3306 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3307 3308 Not Collective 3309 3310 Input Parameters: 3311 + dm - The `DMPLEX` 3312 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3313 - cone - An array of points which are on the in-edges for point `p` 3314 3315 Level: beginner 3316 3317 Note: 3318 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3319 3320 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3321 @*/ 3322 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3323 { 3324 DM_Plex *mesh = (DM_Plex *)dm->data; 3325 PetscInt dof, off, c; 3326 3327 PetscFunctionBegin; 3328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3329 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3330 if (dof) PetscAssertPointer(cone, 3); 3331 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3332 if (PetscDefined(USE_DEBUG)) { 3333 PetscInt pStart, pEnd; 3334 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3335 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3336 for (c = 0; c < dof; ++c) { 3337 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3338 mesh->cones[off + c] = cone[c]; 3339 } 3340 } else { 3341 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3342 } 3343 PetscFunctionReturn(PETSC_SUCCESS); 3344 } 3345 3346 /*@C 3347 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3348 3349 Not Collective 3350 3351 Input Parameters: 3352 + dm - The `DMPLEX` 3353 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3354 3355 Output Parameter: 3356 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3357 integer giving the prescription for cone traversal. 3358 3359 Level: beginner 3360 3361 Note: 3362 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3363 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3364 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3365 with the identity. 3366 3367 Fortran Notes: 3368 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3369 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3370 3371 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3372 @*/ 3373 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3374 { 3375 DM_Plex *mesh = (DM_Plex *)dm->data; 3376 PetscInt off; 3377 3378 PetscFunctionBegin; 3379 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3380 if (PetscDefined(USE_DEBUG)) { 3381 PetscInt dof; 3382 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3383 if (dof) PetscAssertPointer(coneOrientation, 3); 3384 } 3385 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3386 3387 *coneOrientation = &mesh->coneOrientations[off]; 3388 PetscFunctionReturn(PETSC_SUCCESS); 3389 } 3390 3391 /*@ 3392 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3393 3394 Not Collective 3395 3396 Input Parameters: 3397 + dm - The `DMPLEX` 3398 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3399 - coneOrientation - An array of orientations 3400 3401 Level: beginner 3402 3403 Notes: 3404 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3405 3406 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3407 3408 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3409 @*/ 3410 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3411 { 3412 DM_Plex *mesh = (DM_Plex *)dm->data; 3413 PetscInt pStart, pEnd; 3414 PetscInt dof, off, c; 3415 3416 PetscFunctionBegin; 3417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3418 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3419 if (dof) PetscAssertPointer(coneOrientation, 3); 3420 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3421 if (PetscDefined(USE_DEBUG)) { 3422 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3423 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3424 for (c = 0; c < dof; ++c) { 3425 PetscInt cdof, o = coneOrientation[c]; 3426 3427 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3428 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3429 mesh->coneOrientations[off + c] = o; 3430 } 3431 } else { 3432 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3433 } 3434 PetscFunctionReturn(PETSC_SUCCESS); 3435 } 3436 3437 /*@ 3438 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3439 3440 Not Collective 3441 3442 Input Parameters: 3443 + dm - The `DMPLEX` 3444 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3445 . conePos - The local index in the cone where the point should be put 3446 - conePoint - The mesh point to insert 3447 3448 Level: beginner 3449 3450 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3451 @*/ 3452 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3453 { 3454 DM_Plex *mesh = (DM_Plex *)dm->data; 3455 PetscInt pStart, pEnd; 3456 PetscInt dof, off; 3457 3458 PetscFunctionBegin; 3459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3460 if (PetscDefined(USE_DEBUG)) { 3461 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3462 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3463 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3464 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3465 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3466 } 3467 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3468 mesh->cones[off + conePos] = conePoint; 3469 PetscFunctionReturn(PETSC_SUCCESS); 3470 } 3471 3472 /*@ 3473 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3474 3475 Not Collective 3476 3477 Input Parameters: 3478 + dm - The `DMPLEX` 3479 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3480 . conePos - The local index in the cone where the point should be put 3481 - coneOrientation - The point orientation to insert 3482 3483 Level: beginner 3484 3485 Note: 3486 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3487 3488 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3489 @*/ 3490 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3491 { 3492 DM_Plex *mesh = (DM_Plex *)dm->data; 3493 PetscInt pStart, pEnd; 3494 PetscInt dof, off; 3495 3496 PetscFunctionBegin; 3497 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3498 if (PetscDefined(USE_DEBUG)) { 3499 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3500 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3501 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3502 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3503 } 3504 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3505 mesh->coneOrientations[off + conePos] = coneOrientation; 3506 PetscFunctionReturn(PETSC_SUCCESS); 3507 } 3508 3509 /*@C 3510 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3511 3512 Not collective 3513 3514 Input Parameters: 3515 + dm - The DMPlex 3516 - p - The point, which must lie in the chart set with DMPlexSetChart() 3517 3518 Output Parameters: 3519 + cone - An array of points which are on the in-edges for point `p` 3520 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3521 integer giving the prescription for cone traversal. 3522 3523 Level: beginner 3524 3525 Notes: 3526 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3527 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3528 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3529 with the identity. 3530 3531 Fortran Notes: 3532 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3533 `DMPlexRestoreCone()` is not needed/available in C. 3534 3535 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3536 @*/ 3537 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3538 { 3539 DM_Plex *mesh = (DM_Plex *)dm->data; 3540 3541 PetscFunctionBegin; 3542 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3543 if (mesh->tr) { 3544 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3545 } else { 3546 PetscInt off; 3547 if (PetscDefined(USE_DEBUG)) { 3548 PetscInt dof; 3549 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3550 if (dof) { 3551 if (cone) PetscAssertPointer(cone, 3); 3552 if (ornt) PetscAssertPointer(ornt, 4); 3553 } 3554 } 3555 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3556 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3557 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3558 } 3559 PetscFunctionReturn(PETSC_SUCCESS); 3560 } 3561 3562 /*@C 3563 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3564 3565 Not Collective 3566 3567 Input Parameters: 3568 + dm - The DMPlex 3569 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3570 . cone - An array of points which are on the in-edges for point p 3571 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3572 integer giving the prescription for cone traversal. 3573 3574 Level: beginner 3575 3576 Notes: 3577 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3578 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3579 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3580 with the identity. 3581 3582 Fortran Notes: 3583 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3584 `DMPlexRestoreCone()` is not needed/available in C. 3585 3586 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3587 @*/ 3588 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3589 { 3590 DM_Plex *mesh = (DM_Plex *)dm->data; 3591 3592 PetscFunctionBegin; 3593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3594 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3595 PetscFunctionReturn(PETSC_SUCCESS); 3596 } 3597 3598 /*@ 3599 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3600 3601 Not Collective 3602 3603 Input Parameters: 3604 + dm - The `DMPLEX` 3605 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3606 3607 Output Parameter: 3608 . size - The support size for point `p` 3609 3610 Level: beginner 3611 3612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3613 @*/ 3614 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3615 { 3616 DM_Plex *mesh = (DM_Plex *)dm->data; 3617 3618 PetscFunctionBegin; 3619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3620 PetscAssertPointer(size, 3); 3621 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3622 PetscFunctionReturn(PETSC_SUCCESS); 3623 } 3624 3625 /*@ 3626 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3627 3628 Not Collective 3629 3630 Input Parameters: 3631 + dm - The `DMPLEX` 3632 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3633 - size - The support size for point `p` 3634 3635 Level: beginner 3636 3637 Note: 3638 This should be called after `DMPlexSetChart()`. 3639 3640 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3641 @*/ 3642 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3643 { 3644 DM_Plex *mesh = (DM_Plex *)dm->data; 3645 3646 PetscFunctionBegin; 3647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3648 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3649 PetscFunctionReturn(PETSC_SUCCESS); 3650 } 3651 3652 /*@C 3653 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3654 3655 Not Collective 3656 3657 Input Parameters: 3658 + dm - The `DMPLEX` 3659 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3660 3661 Output Parameter: 3662 . support - An array of points which are on the out-edges for point `p` 3663 3664 Level: beginner 3665 3666 Fortran Notes: 3667 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3668 `DMPlexRestoreSupport()` is not needed/available in C. 3669 3670 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3671 @*/ 3672 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3673 { 3674 DM_Plex *mesh = (DM_Plex *)dm->data; 3675 PetscInt off; 3676 3677 PetscFunctionBegin; 3678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3679 PetscAssertPointer(support, 3); 3680 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3681 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3682 PetscFunctionReturn(PETSC_SUCCESS); 3683 } 3684 3685 /*@ 3686 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3687 3688 Not Collective 3689 3690 Input Parameters: 3691 + dm - The `DMPLEX` 3692 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3693 - support - An array of points which are on the out-edges for point `p` 3694 3695 Level: beginner 3696 3697 Note: 3698 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3699 3700 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3701 @*/ 3702 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3703 { 3704 DM_Plex *mesh = (DM_Plex *)dm->data; 3705 PetscInt pStart, pEnd; 3706 PetscInt dof, off, c; 3707 3708 PetscFunctionBegin; 3709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3710 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3711 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3712 if (dof) PetscAssertPointer(support, 3); 3713 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3714 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3715 for (c = 0; c < dof; ++c) { 3716 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3717 mesh->supports[off + c] = support[c]; 3718 } 3719 PetscFunctionReturn(PETSC_SUCCESS); 3720 } 3721 3722 /*@ 3723 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3724 3725 Not Collective 3726 3727 Input Parameters: 3728 + dm - The `DMPLEX` 3729 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3730 . supportPos - The local index in the cone where the point should be put 3731 - supportPoint - The mesh point to insert 3732 3733 Level: beginner 3734 3735 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3736 @*/ 3737 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3738 { 3739 DM_Plex *mesh = (DM_Plex *)dm->data; 3740 PetscInt pStart, pEnd; 3741 PetscInt dof, off; 3742 3743 PetscFunctionBegin; 3744 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3745 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3746 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3747 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3748 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3749 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3750 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3751 mesh->supports[off + supportPos] = supportPoint; 3752 PetscFunctionReturn(PETSC_SUCCESS); 3753 } 3754 3755 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3756 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3757 { 3758 switch (ct) { 3759 case DM_POLYTOPE_SEGMENT: 3760 if (o == -1) return -2; 3761 break; 3762 case DM_POLYTOPE_TRIANGLE: 3763 if (o == -3) return -1; 3764 if (o == -2) return -3; 3765 if (o == -1) return -2; 3766 break; 3767 case DM_POLYTOPE_QUADRILATERAL: 3768 if (o == -4) return -2; 3769 if (o == -3) return -1; 3770 if (o == -2) return -4; 3771 if (o == -1) return -3; 3772 break; 3773 default: 3774 return o; 3775 } 3776 return o; 3777 } 3778 3779 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3780 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3781 { 3782 switch (ct) { 3783 case DM_POLYTOPE_SEGMENT: 3784 if ((o == -2) || (o == 1)) return -1; 3785 if (o == -1) return 0; 3786 break; 3787 case DM_POLYTOPE_TRIANGLE: 3788 if (o == -3) return -2; 3789 if (o == -2) return -1; 3790 if (o == -1) return -3; 3791 break; 3792 case DM_POLYTOPE_QUADRILATERAL: 3793 if (o == -4) return -2; 3794 if (o == -3) return -1; 3795 if (o == -2) return -4; 3796 if (o == -1) return -3; 3797 break; 3798 default: 3799 return o; 3800 } 3801 return o; 3802 } 3803 3804 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3805 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3806 { 3807 PetscInt pStart, pEnd, p; 3808 3809 PetscFunctionBegin; 3810 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3811 for (p = pStart; p < pEnd; ++p) { 3812 const PetscInt *cone, *ornt; 3813 PetscInt coneSize, c; 3814 3815 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3816 PetscCall(DMPlexGetCone(dm, p, &cone)); 3817 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3818 for (c = 0; c < coneSize; ++c) { 3819 DMPolytopeType ct; 3820 const PetscInt o = ornt[c]; 3821 3822 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3823 switch (ct) { 3824 case DM_POLYTOPE_SEGMENT: 3825 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3826 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3827 break; 3828 case DM_POLYTOPE_TRIANGLE: 3829 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3830 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3831 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3832 break; 3833 case DM_POLYTOPE_QUADRILATERAL: 3834 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3835 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3836 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3837 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3838 break; 3839 default: 3840 break; 3841 } 3842 } 3843 } 3844 PetscFunctionReturn(PETSC_SUCCESS); 3845 } 3846 3847 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3848 { 3849 DM_Plex *mesh = (DM_Plex *)dm->data; 3850 3851 PetscFunctionBeginHot; 3852 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3853 if (useCone) { 3854 PetscCall(DMPlexGetConeSize(dm, p, size)); 3855 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3856 } else { 3857 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3858 PetscCall(DMPlexGetSupport(dm, p, arr)); 3859 } 3860 } else { 3861 if (useCone) { 3862 const PetscSection s = mesh->coneSection; 3863 const PetscInt ps = p - s->pStart; 3864 const PetscInt off = s->atlasOff[ps]; 3865 3866 *size = s->atlasDof[ps]; 3867 *arr = mesh->cones + off; 3868 *ornt = mesh->coneOrientations + off; 3869 } else { 3870 const PetscSection s = mesh->supportSection; 3871 const PetscInt ps = p - s->pStart; 3872 const PetscInt off = s->atlasOff[ps]; 3873 3874 *size = s->atlasDof[ps]; 3875 *arr = mesh->supports + off; 3876 } 3877 } 3878 PetscFunctionReturn(PETSC_SUCCESS); 3879 } 3880 3881 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3882 { 3883 DM_Plex *mesh = (DM_Plex *)dm->data; 3884 3885 PetscFunctionBeginHot; 3886 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3887 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3888 } 3889 PetscFunctionReturn(PETSC_SUCCESS); 3890 } 3891 3892 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3893 { 3894 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3895 PetscInt *closure; 3896 const PetscInt *tmp = NULL, *tmpO = NULL; 3897 PetscInt off = 0, tmpSize, t; 3898 3899 PetscFunctionBeginHot; 3900 if (ornt) { 3901 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3902 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 3903 } 3904 if (*points) { 3905 closure = *points; 3906 } else { 3907 PetscInt maxConeSize, maxSupportSize; 3908 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3909 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3910 } 3911 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3912 if (ct == DM_POLYTOPE_UNKNOWN) { 3913 closure[off++] = p; 3914 closure[off++] = 0; 3915 for (t = 0; t < tmpSize; ++t) { 3916 closure[off++] = tmp[t]; 3917 closure[off++] = tmpO ? tmpO[t] : 0; 3918 } 3919 } else { 3920 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3921 3922 /* We assume that cells with a valid type have faces with a valid type */ 3923 closure[off++] = p; 3924 closure[off++] = ornt; 3925 for (t = 0; t < tmpSize; ++t) { 3926 DMPolytopeType ft; 3927 3928 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3929 closure[off++] = tmp[arr[t]]; 3930 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3931 } 3932 } 3933 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3934 if (numPoints) *numPoints = tmpSize + 1; 3935 if (points) *points = closure; 3936 PetscFunctionReturn(PETSC_SUCCESS); 3937 } 3938 3939 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3940 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3941 { 3942 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3943 const PetscInt *cone, *ornt; 3944 PetscInt *pts, *closure = NULL; 3945 DMPolytopeType ft; 3946 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3947 PetscInt dim, coneSize, c, d, clSize, cl; 3948 3949 PetscFunctionBeginHot; 3950 PetscCall(DMGetDimension(dm, &dim)); 3951 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3952 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3953 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3954 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3955 maxSize = PetscMax(coneSeries, supportSeries); 3956 if (*points) { 3957 pts = *points; 3958 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3959 c = 0; 3960 pts[c++] = point; 3961 pts[c++] = o; 3962 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3963 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3964 for (cl = 0; cl < clSize * 2; cl += 2) { 3965 pts[c++] = closure[cl]; 3966 pts[c++] = closure[cl + 1]; 3967 } 3968 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3969 for (cl = 0; cl < clSize * 2; cl += 2) { 3970 pts[c++] = closure[cl]; 3971 pts[c++] = closure[cl + 1]; 3972 } 3973 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3974 for (d = 2; d < coneSize; ++d) { 3975 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3976 pts[c++] = cone[arr[d * 2 + 0]]; 3977 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3978 } 3979 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3980 if (dim >= 3) { 3981 for (d = 2; d < coneSize; ++d) { 3982 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3983 const PetscInt *fcone, *fornt; 3984 PetscInt fconeSize, fc, i; 3985 3986 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3987 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3988 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3989 for (fc = 0; fc < fconeSize; ++fc) { 3990 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3991 const PetscInt co = farr[fc * 2 + 1]; 3992 3993 for (i = 0; i < c; i += 2) 3994 if (pts[i] == cp) break; 3995 if (i == c) { 3996 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3997 pts[c++] = cp; 3998 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3999 } 4000 } 4001 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4002 } 4003 } 4004 *numPoints = c / 2; 4005 *points = pts; 4006 PetscFunctionReturn(PETSC_SUCCESS); 4007 } 4008 4009 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4010 { 4011 DMPolytopeType ct; 4012 PetscInt *closure, *fifo; 4013 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4014 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4015 PetscInt depth, maxSize; 4016 4017 PetscFunctionBeginHot; 4018 PetscCall(DMPlexGetDepth(dm, &depth)); 4019 if (depth == 1) { 4020 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4021 PetscFunctionReturn(PETSC_SUCCESS); 4022 } 4023 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4024 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4025 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4026 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4027 PetscFunctionReturn(PETSC_SUCCESS); 4028 } 4029 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4030 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4031 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4032 maxSize = PetscMax(coneSeries, supportSeries); 4033 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4034 if (*points) { 4035 closure = *points; 4036 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4037 closure[closureSize++] = p; 4038 closure[closureSize++] = ornt; 4039 fifo[fifoSize++] = p; 4040 fifo[fifoSize++] = ornt; 4041 fifo[fifoSize++] = ct; 4042 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4043 while (fifoSize - fifoStart) { 4044 const PetscInt q = fifo[fifoStart++]; 4045 const PetscInt o = fifo[fifoStart++]; 4046 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4047 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4048 const PetscInt *tmp, *tmpO = NULL; 4049 PetscInt tmpSize, t; 4050 4051 if (PetscDefined(USE_DEBUG)) { 4052 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4053 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 4054 } 4055 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4056 for (t = 0; t < tmpSize; ++t) { 4057 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4058 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4059 const PetscInt cp = tmp[ip]; 4060 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4061 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4062 PetscInt c; 4063 4064 /* Check for duplicate */ 4065 for (c = 0; c < closureSize; c += 2) { 4066 if (closure[c] == cp) break; 4067 } 4068 if (c == closureSize) { 4069 closure[closureSize++] = cp; 4070 closure[closureSize++] = co; 4071 fifo[fifoSize++] = cp; 4072 fifo[fifoSize++] = co; 4073 fifo[fifoSize++] = ct; 4074 } 4075 } 4076 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4077 } 4078 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4079 if (numPoints) *numPoints = closureSize / 2; 4080 if (points) *points = closure; 4081 PetscFunctionReturn(PETSC_SUCCESS); 4082 } 4083 4084 /*@C 4085 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4086 4087 Not Collective 4088 4089 Input Parameters: 4090 + dm - The `DMPLEX` 4091 . p - The mesh point 4092 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4093 4094 Input/Output Parameter: 4095 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4096 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4097 4098 Output Parameter: 4099 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4100 4101 Level: beginner 4102 4103 Note: 4104 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4105 4106 Fortran Notes: 4107 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4108 4109 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4110 @*/ 4111 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4112 { 4113 PetscFunctionBeginHot; 4114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4115 if (numPoints) PetscAssertPointer(numPoints, 4); 4116 if (points) PetscAssertPointer(points, 5); 4117 if (PetscDefined(USE_DEBUG)) { 4118 PetscInt pStart, pEnd; 4119 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4120 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4121 } 4122 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4123 PetscFunctionReturn(PETSC_SUCCESS); 4124 } 4125 4126 /*@C 4127 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4128 4129 Not Collective 4130 4131 Input Parameters: 4132 + dm - The `DMPLEX` 4133 . p - The mesh point 4134 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4135 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4136 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4137 4138 Level: beginner 4139 4140 Note: 4141 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4142 4143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4144 @*/ 4145 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4146 { 4147 PetscFunctionBeginHot; 4148 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4149 if (numPoints) *numPoints = 0; 4150 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4151 PetscFunctionReturn(PETSC_SUCCESS); 4152 } 4153 4154 /*@ 4155 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4156 4157 Not Collective 4158 4159 Input Parameter: 4160 . dm - The `DMPLEX` 4161 4162 Output Parameters: 4163 + maxConeSize - The maximum number of in-edges 4164 - maxSupportSize - The maximum number of out-edges 4165 4166 Level: beginner 4167 4168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4169 @*/ 4170 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4171 { 4172 DM_Plex *mesh = (DM_Plex *)dm->data; 4173 4174 PetscFunctionBegin; 4175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4176 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4177 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4178 PetscFunctionReturn(PETSC_SUCCESS); 4179 } 4180 4181 PetscErrorCode DMSetUp_Plex(DM dm) 4182 { 4183 DM_Plex *mesh = (DM_Plex *)dm->data; 4184 PetscInt size, maxSupportSize; 4185 4186 PetscFunctionBegin; 4187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4188 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4189 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4190 PetscCall(PetscMalloc1(size, &mesh->cones)); 4191 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4192 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4193 if (maxSupportSize) { 4194 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4195 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4196 PetscCall(PetscMalloc1(size, &mesh->supports)); 4197 } 4198 PetscFunctionReturn(PETSC_SUCCESS); 4199 } 4200 4201 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4202 { 4203 PetscFunctionBegin; 4204 if (subdm) PetscCall(DMClone(dm, subdm)); 4205 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4206 if (subdm) (*subdm)->useNatural = dm->useNatural; 4207 if (dm->useNatural && dm->sfMigration) { 4208 PetscSF sfNatural; 4209 4210 (*subdm)->sfMigration = dm->sfMigration; 4211 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4212 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4213 (*subdm)->sfNatural = sfNatural; 4214 } 4215 PetscFunctionReturn(PETSC_SUCCESS); 4216 } 4217 4218 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4219 { 4220 PetscInt i = 0; 4221 4222 PetscFunctionBegin; 4223 PetscCall(DMClone(dms[0], superdm)); 4224 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4225 (*superdm)->useNatural = PETSC_FALSE; 4226 for (i = 0; i < len; i++) { 4227 if (dms[i]->useNatural && dms[i]->sfMigration) { 4228 PetscSF sfNatural; 4229 4230 (*superdm)->sfMigration = dms[i]->sfMigration; 4231 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4232 (*superdm)->useNatural = PETSC_TRUE; 4233 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4234 (*superdm)->sfNatural = sfNatural; 4235 break; 4236 } 4237 } 4238 PetscFunctionReturn(PETSC_SUCCESS); 4239 } 4240 4241 /*@ 4242 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4243 4244 Not Collective 4245 4246 Input Parameter: 4247 . dm - The `DMPLEX` 4248 4249 Level: beginner 4250 4251 Note: 4252 This should be called after all calls to `DMPlexSetCone()` 4253 4254 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4255 @*/ 4256 PetscErrorCode DMPlexSymmetrize(DM dm) 4257 { 4258 DM_Plex *mesh = (DM_Plex *)dm->data; 4259 PetscInt *offsets; 4260 PetscInt supportSize; 4261 PetscInt pStart, pEnd, p; 4262 4263 PetscFunctionBegin; 4264 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4265 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4266 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4267 /* Calculate support sizes */ 4268 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4269 for (p = pStart; p < pEnd; ++p) { 4270 PetscInt dof, off, c; 4271 4272 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4273 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4274 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4275 } 4276 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4277 /* Calculate supports */ 4278 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4279 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4280 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4281 for (p = pStart; p < pEnd; ++p) { 4282 PetscInt dof, off, c; 4283 4284 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4285 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4286 for (c = off; c < off + dof; ++c) { 4287 const PetscInt q = mesh->cones[c]; 4288 PetscInt offS; 4289 4290 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4291 4292 mesh->supports[offS + offsets[q]] = p; 4293 ++offsets[q]; 4294 } 4295 } 4296 PetscCall(PetscFree(offsets)); 4297 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4298 PetscFunctionReturn(PETSC_SUCCESS); 4299 } 4300 4301 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4302 { 4303 IS stratumIS; 4304 4305 PetscFunctionBegin; 4306 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4307 if (PetscDefined(USE_DEBUG)) { 4308 PetscInt qStart, qEnd, numLevels, level; 4309 PetscBool overlap = PETSC_FALSE; 4310 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4311 for (level = 0; level < numLevels; level++) { 4312 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4313 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4314 overlap = PETSC_TRUE; 4315 break; 4316 } 4317 } 4318 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 4319 } 4320 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4321 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4322 PetscCall(ISDestroy(&stratumIS)); 4323 PetscFunctionReturn(PETSC_SUCCESS); 4324 } 4325 4326 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4327 { 4328 PetscInt *pMin, *pMax; 4329 PetscInt pStart, pEnd; 4330 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4331 4332 PetscFunctionBegin; 4333 { 4334 DMLabel label2; 4335 4336 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4337 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4338 } 4339 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4340 for (PetscInt p = pStart; p < pEnd; ++p) { 4341 DMPolytopeType ct; 4342 4343 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4344 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4345 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4346 } 4347 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4348 for (PetscInt d = dmin; d <= dmax; ++d) { 4349 pMin[d] = PETSC_MAX_INT; 4350 pMax[d] = PETSC_MIN_INT; 4351 } 4352 for (PetscInt p = pStart; p < pEnd; ++p) { 4353 DMPolytopeType ct; 4354 PetscInt d; 4355 4356 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4357 d = DMPolytopeTypeGetDim(ct); 4358 pMin[d] = PetscMin(p, pMin[d]); 4359 pMax[d] = PetscMax(p, pMax[d]); 4360 } 4361 for (PetscInt d = dmin; d <= dmax; ++d) { 4362 if (pMin[d] > pMax[d]) continue; 4363 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4364 } 4365 PetscCall(PetscFree2(pMin, pMax)); 4366 PetscFunctionReturn(PETSC_SUCCESS); 4367 } 4368 4369 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4370 { 4371 PetscInt pStart, pEnd; 4372 PetscInt numRoots = 0, numLeaves = 0; 4373 4374 PetscFunctionBegin; 4375 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4376 { 4377 /* Initialize roots and count leaves */ 4378 PetscInt sMin = PETSC_MAX_INT; 4379 PetscInt sMax = PETSC_MIN_INT; 4380 PetscInt coneSize, supportSize; 4381 4382 for (PetscInt p = pStart; p < pEnd; ++p) { 4383 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4384 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4385 if (!coneSize && supportSize) { 4386 sMin = PetscMin(p, sMin); 4387 sMax = PetscMax(p, sMax); 4388 ++numRoots; 4389 } else if (!supportSize && coneSize) { 4390 ++numLeaves; 4391 } else if (!supportSize && !coneSize) { 4392 /* Isolated points */ 4393 sMin = PetscMin(p, sMin); 4394 sMax = PetscMax(p, sMax); 4395 } 4396 } 4397 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4398 } 4399 4400 if (numRoots + numLeaves == (pEnd - pStart)) { 4401 PetscInt sMin = PETSC_MAX_INT; 4402 PetscInt sMax = PETSC_MIN_INT; 4403 PetscInt coneSize, supportSize; 4404 4405 for (PetscInt p = pStart; p < pEnd; ++p) { 4406 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4407 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4408 if (!supportSize && coneSize) { 4409 sMin = PetscMin(p, sMin); 4410 sMax = PetscMax(p, sMax); 4411 } 4412 } 4413 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4414 } else { 4415 PetscInt level = 0; 4416 PetscInt qStart, qEnd; 4417 4418 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4419 while (qEnd > qStart) { 4420 PetscInt sMin = PETSC_MAX_INT; 4421 PetscInt sMax = PETSC_MIN_INT; 4422 4423 for (PetscInt q = qStart; q < qEnd; ++q) { 4424 const PetscInt *support; 4425 PetscInt supportSize; 4426 4427 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4428 PetscCall(DMPlexGetSupport(dm, q, &support)); 4429 for (PetscInt s = 0; s < supportSize; ++s) { 4430 sMin = PetscMin(support[s], sMin); 4431 sMax = PetscMax(support[s], sMax); 4432 } 4433 } 4434 PetscCall(DMLabelGetNumValues(label, &level)); 4435 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4436 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4437 } 4438 } 4439 PetscFunctionReturn(PETSC_SUCCESS); 4440 } 4441 4442 /*@ 4443 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4444 4445 Collective 4446 4447 Input Parameter: 4448 . dm - The `DMPLEX` 4449 4450 Level: beginner 4451 4452 Notes: 4453 The strata group all points of the same grade, and this function calculates the strata. This 4454 grade can be seen as the height (or depth) of the point in the DAG. 4455 4456 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4457 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4458 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4459 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4460 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4461 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4462 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4463 4464 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4465 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4466 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 4467 to interpolate only that one (e0), so that 4468 .vb 4469 cone(c0) = {e0, v2} 4470 cone(e0) = {v0, v1} 4471 .ve 4472 If `DMPlexStratify()` is run on this mesh, it will give depths 4473 .vb 4474 depth 0 = {v0, v1, v2} 4475 depth 1 = {e0, c0} 4476 .ve 4477 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4478 4479 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4480 4481 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4482 @*/ 4483 PetscErrorCode DMPlexStratify(DM dm) 4484 { 4485 DM_Plex *mesh = (DM_Plex *)dm->data; 4486 DMLabel label; 4487 PetscBool flg = PETSC_FALSE; 4488 4489 PetscFunctionBegin; 4490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4491 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4492 4493 // Create depth label 4494 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4495 PetscCall(DMCreateLabel(dm, "depth")); 4496 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4497 4498 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4499 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4500 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4501 4502 { /* just in case there is an empty process */ 4503 PetscInt numValues, maxValues = 0, v; 4504 4505 PetscCall(DMLabelGetNumValues(label, &numValues)); 4506 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4507 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4508 } 4509 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4510 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4511 PetscFunctionReturn(PETSC_SUCCESS); 4512 } 4513 4514 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4515 { 4516 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4517 PetscInt dim, depth, pheight, coneSize; 4518 4519 PetscFunctionBeginHot; 4520 PetscCall(DMGetDimension(dm, &dim)); 4521 PetscCall(DMPlexGetDepth(dm, &depth)); 4522 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4523 pheight = depth - pdepth; 4524 if (depth <= 1) { 4525 switch (pdepth) { 4526 case 0: 4527 ct = DM_POLYTOPE_POINT; 4528 break; 4529 case 1: 4530 switch (coneSize) { 4531 case 2: 4532 ct = DM_POLYTOPE_SEGMENT; 4533 break; 4534 case 3: 4535 ct = DM_POLYTOPE_TRIANGLE; 4536 break; 4537 case 4: 4538 switch (dim) { 4539 case 2: 4540 ct = DM_POLYTOPE_QUADRILATERAL; 4541 break; 4542 case 3: 4543 ct = DM_POLYTOPE_TETRAHEDRON; 4544 break; 4545 default: 4546 break; 4547 } 4548 break; 4549 case 5: 4550 ct = DM_POLYTOPE_PYRAMID; 4551 break; 4552 case 6: 4553 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4554 break; 4555 case 8: 4556 ct = DM_POLYTOPE_HEXAHEDRON; 4557 break; 4558 default: 4559 break; 4560 } 4561 } 4562 } else { 4563 if (pdepth == 0) { 4564 ct = DM_POLYTOPE_POINT; 4565 } else if (pheight == 0) { 4566 switch (dim) { 4567 case 1: 4568 switch (coneSize) { 4569 case 2: 4570 ct = DM_POLYTOPE_SEGMENT; 4571 break; 4572 default: 4573 break; 4574 } 4575 break; 4576 case 2: 4577 switch (coneSize) { 4578 case 3: 4579 ct = DM_POLYTOPE_TRIANGLE; 4580 break; 4581 case 4: 4582 ct = DM_POLYTOPE_QUADRILATERAL; 4583 break; 4584 default: 4585 break; 4586 } 4587 break; 4588 case 3: 4589 switch (coneSize) { 4590 case 4: 4591 ct = DM_POLYTOPE_TETRAHEDRON; 4592 break; 4593 case 5: { 4594 const PetscInt *cone; 4595 PetscInt faceConeSize; 4596 4597 PetscCall(DMPlexGetCone(dm, p, &cone)); 4598 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4599 switch (faceConeSize) { 4600 case 3: 4601 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4602 break; 4603 case 4: 4604 ct = DM_POLYTOPE_PYRAMID; 4605 break; 4606 } 4607 } break; 4608 case 6: 4609 ct = DM_POLYTOPE_HEXAHEDRON; 4610 break; 4611 default: 4612 break; 4613 } 4614 break; 4615 default: 4616 break; 4617 } 4618 } else if (pheight > 0) { 4619 switch (coneSize) { 4620 case 2: 4621 ct = DM_POLYTOPE_SEGMENT; 4622 break; 4623 case 3: 4624 ct = DM_POLYTOPE_TRIANGLE; 4625 break; 4626 case 4: 4627 ct = DM_POLYTOPE_QUADRILATERAL; 4628 break; 4629 default: 4630 break; 4631 } 4632 } 4633 } 4634 *pt = ct; 4635 PetscFunctionReturn(PETSC_SUCCESS); 4636 } 4637 4638 /*@ 4639 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4640 4641 Collective 4642 4643 Input Parameter: 4644 . dm - The `DMPLEX` 4645 4646 Level: developer 4647 4648 Note: 4649 This function is normally called automatically when a cell type is requested. It creates an 4650 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4651 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4652 4653 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4654 4655 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4656 @*/ 4657 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4658 { 4659 DM_Plex *mesh; 4660 DMLabel ctLabel; 4661 PetscInt pStart, pEnd, p; 4662 4663 PetscFunctionBegin; 4664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4665 mesh = (DM_Plex *)dm->data; 4666 PetscCall(DMCreateLabel(dm, "celltype")); 4667 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4668 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4669 PetscCall(PetscFree(mesh->cellTypes)); 4670 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4671 for (p = pStart; p < pEnd; ++p) { 4672 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4673 PetscInt pdepth; 4674 4675 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4676 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4677 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4678 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4679 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4680 } 4681 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4682 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4683 PetscFunctionReturn(PETSC_SUCCESS); 4684 } 4685 4686 /*@C 4687 DMPlexGetJoin - Get an array for the join of the set of points 4688 4689 Not Collective 4690 4691 Input Parameters: 4692 + dm - The `DMPLEX` object 4693 . numPoints - The number of input points for the join 4694 - points - The input points 4695 4696 Output Parameters: 4697 + numCoveredPoints - The number of points in the join 4698 - coveredPoints - The points in the join 4699 4700 Level: intermediate 4701 4702 Note: 4703 Currently, this is restricted to a single level join 4704 4705 Fortran Notes: 4706 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4707 4708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4709 @*/ 4710 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4711 { 4712 DM_Plex *mesh = (DM_Plex *)dm->data; 4713 PetscInt *join[2]; 4714 PetscInt joinSize, i = 0; 4715 PetscInt dof, off, p, c, m; 4716 PetscInt maxSupportSize; 4717 4718 PetscFunctionBegin; 4719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4720 PetscAssertPointer(points, 3); 4721 PetscAssertPointer(numCoveredPoints, 4); 4722 PetscAssertPointer(coveredPoints, 5); 4723 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4724 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4725 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4726 /* Copy in support of first point */ 4727 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4728 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4729 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4730 /* Check each successive support */ 4731 for (p = 1; p < numPoints; ++p) { 4732 PetscInt newJoinSize = 0; 4733 4734 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4735 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4736 for (c = 0; c < dof; ++c) { 4737 const PetscInt point = mesh->supports[off + c]; 4738 4739 for (m = 0; m < joinSize; ++m) { 4740 if (point == join[i][m]) { 4741 join[1 - i][newJoinSize++] = point; 4742 break; 4743 } 4744 } 4745 } 4746 joinSize = newJoinSize; 4747 i = 1 - i; 4748 } 4749 *numCoveredPoints = joinSize; 4750 *coveredPoints = join[i]; 4751 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4752 PetscFunctionReturn(PETSC_SUCCESS); 4753 } 4754 4755 /*@C 4756 DMPlexRestoreJoin - Restore an array for the join of the set of points 4757 4758 Not Collective 4759 4760 Input Parameters: 4761 + dm - The `DMPLEX` object 4762 . numPoints - The number of input points for the join 4763 - points - The input points 4764 4765 Output Parameters: 4766 + numCoveredPoints - The number of points in the join 4767 - coveredPoints - The points in the join 4768 4769 Level: intermediate 4770 4771 Fortran Notes: 4772 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4773 4774 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4775 @*/ 4776 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4777 { 4778 PetscFunctionBegin; 4779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4780 if (points) PetscAssertPointer(points, 3); 4781 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4782 PetscAssertPointer(coveredPoints, 5); 4783 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4784 if (numCoveredPoints) *numCoveredPoints = 0; 4785 PetscFunctionReturn(PETSC_SUCCESS); 4786 } 4787 4788 /*@C 4789 DMPlexGetFullJoin - Get an array for the join of the set of points 4790 4791 Not Collective 4792 4793 Input Parameters: 4794 + dm - The `DMPLEX` object 4795 . numPoints - The number of input points for the join 4796 - points - The input points 4797 4798 Output Parameters: 4799 + numCoveredPoints - The number of points in the join 4800 - coveredPoints - The points in the join 4801 4802 Level: intermediate 4803 4804 Fortran Notes: 4805 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4806 4807 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4808 @*/ 4809 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4810 { 4811 PetscInt *offsets, **closures; 4812 PetscInt *join[2]; 4813 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4814 PetscInt p, d, c, m, ms; 4815 4816 PetscFunctionBegin; 4817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4818 PetscAssertPointer(points, 3); 4819 PetscAssertPointer(numCoveredPoints, 4); 4820 PetscAssertPointer(coveredPoints, 5); 4821 4822 PetscCall(DMPlexGetDepth(dm, &depth)); 4823 PetscCall(PetscCalloc1(numPoints, &closures)); 4824 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4825 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4826 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4827 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4828 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4829 4830 for (p = 0; p < numPoints; ++p) { 4831 PetscInt closureSize; 4832 4833 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4834 4835 offsets[p * (depth + 2) + 0] = 0; 4836 for (d = 0; d < depth + 1; ++d) { 4837 PetscInt pStart, pEnd, i; 4838 4839 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4840 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4841 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4842 offsets[p * (depth + 2) + d + 1] = i; 4843 break; 4844 } 4845 } 4846 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4847 } 4848 PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize); 4849 } 4850 for (d = 0; d < depth + 1; ++d) { 4851 PetscInt dof; 4852 4853 /* Copy in support of first point */ 4854 dof = offsets[d + 1] - offsets[d]; 4855 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4856 /* Check each successive cone */ 4857 for (p = 1; p < numPoints && joinSize; ++p) { 4858 PetscInt newJoinSize = 0; 4859 4860 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4861 for (c = 0; c < dof; ++c) { 4862 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4863 4864 for (m = 0; m < joinSize; ++m) { 4865 if (point == join[i][m]) { 4866 join[1 - i][newJoinSize++] = point; 4867 break; 4868 } 4869 } 4870 } 4871 joinSize = newJoinSize; 4872 i = 1 - i; 4873 } 4874 if (joinSize) break; 4875 } 4876 *numCoveredPoints = joinSize; 4877 *coveredPoints = join[i]; 4878 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4879 PetscCall(PetscFree(closures)); 4880 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4881 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4882 PetscFunctionReturn(PETSC_SUCCESS); 4883 } 4884 4885 /*@C 4886 DMPlexGetMeet - Get an array for the meet of the set of points 4887 4888 Not Collective 4889 4890 Input Parameters: 4891 + dm - The `DMPLEX` object 4892 . numPoints - The number of input points for the meet 4893 - points - The input points 4894 4895 Output Parameters: 4896 + numCoveringPoints - The number of points in the meet 4897 - coveringPoints - The points in the meet 4898 4899 Level: intermediate 4900 4901 Note: 4902 Currently, this is restricted to a single level meet 4903 4904 Fortran Notes: 4905 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4906 4907 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4908 @*/ 4909 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4910 { 4911 DM_Plex *mesh = (DM_Plex *)dm->data; 4912 PetscInt *meet[2]; 4913 PetscInt meetSize, i = 0; 4914 PetscInt dof, off, p, c, m; 4915 PetscInt maxConeSize; 4916 4917 PetscFunctionBegin; 4918 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4919 PetscAssertPointer(points, 3); 4920 PetscAssertPointer(numCoveringPoints, 4); 4921 PetscAssertPointer(coveringPoints, 5); 4922 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4923 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4924 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4925 /* Copy in cone of first point */ 4926 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4927 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4928 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4929 /* Check each successive cone */ 4930 for (p = 1; p < numPoints; ++p) { 4931 PetscInt newMeetSize = 0; 4932 4933 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4934 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4935 for (c = 0; c < dof; ++c) { 4936 const PetscInt point = mesh->cones[off + c]; 4937 4938 for (m = 0; m < meetSize; ++m) { 4939 if (point == meet[i][m]) { 4940 meet[1 - i][newMeetSize++] = point; 4941 break; 4942 } 4943 } 4944 } 4945 meetSize = newMeetSize; 4946 i = 1 - i; 4947 } 4948 *numCoveringPoints = meetSize; 4949 *coveringPoints = meet[i]; 4950 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4951 PetscFunctionReturn(PETSC_SUCCESS); 4952 } 4953 4954 /*@C 4955 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4956 4957 Not Collective 4958 4959 Input Parameters: 4960 + dm - The `DMPLEX` object 4961 . numPoints - The number of input points for the meet 4962 - points - The input points 4963 4964 Output Parameters: 4965 + numCoveredPoints - The number of points in the meet 4966 - coveredPoints - The points in the meet 4967 4968 Level: intermediate 4969 4970 Fortran Notes: 4971 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4972 4973 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4974 @*/ 4975 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4976 { 4977 PetscFunctionBegin; 4978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4979 if (points) PetscAssertPointer(points, 3); 4980 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4981 PetscAssertPointer(coveredPoints, 5); 4982 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4983 if (numCoveredPoints) *numCoveredPoints = 0; 4984 PetscFunctionReturn(PETSC_SUCCESS); 4985 } 4986 4987 /*@C 4988 DMPlexGetFullMeet - Get an array for the meet of the set of points 4989 4990 Not Collective 4991 4992 Input Parameters: 4993 + dm - The `DMPLEX` object 4994 . numPoints - The number of input points for the meet 4995 - points - The input points 4996 4997 Output Parameters: 4998 + numCoveredPoints - The number of points in the meet 4999 - coveredPoints - The points in the meet 5000 5001 Level: intermediate 5002 5003 Fortran Notes: 5004 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5005 5006 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5007 @*/ 5008 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 5009 { 5010 PetscInt *offsets, **closures; 5011 PetscInt *meet[2]; 5012 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5013 PetscInt p, h, c, m, mc; 5014 5015 PetscFunctionBegin; 5016 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5017 PetscAssertPointer(points, 3); 5018 PetscAssertPointer(numCoveredPoints, 4); 5019 PetscAssertPointer(coveredPoints, 5); 5020 5021 PetscCall(DMPlexGetDepth(dm, &height)); 5022 PetscCall(PetscMalloc1(numPoints, &closures)); 5023 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5024 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5025 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5026 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5027 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5028 5029 for (p = 0; p < numPoints; ++p) { 5030 PetscInt closureSize; 5031 5032 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5033 5034 offsets[p * (height + 2) + 0] = 0; 5035 for (h = 0; h < height + 1; ++h) { 5036 PetscInt pStart, pEnd, i; 5037 5038 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5039 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5040 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5041 offsets[p * (height + 2) + h + 1] = i; 5042 break; 5043 } 5044 } 5045 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5046 } 5047 PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize); 5048 } 5049 for (h = 0; h < height + 1; ++h) { 5050 PetscInt dof; 5051 5052 /* Copy in cone of first point */ 5053 dof = offsets[h + 1] - offsets[h]; 5054 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5055 /* Check each successive cone */ 5056 for (p = 1; p < numPoints && meetSize; ++p) { 5057 PetscInt newMeetSize = 0; 5058 5059 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5060 for (c = 0; c < dof; ++c) { 5061 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5062 5063 for (m = 0; m < meetSize; ++m) { 5064 if (point == meet[i][m]) { 5065 meet[1 - i][newMeetSize++] = point; 5066 break; 5067 } 5068 } 5069 } 5070 meetSize = newMeetSize; 5071 i = 1 - i; 5072 } 5073 if (meetSize) break; 5074 } 5075 *numCoveredPoints = meetSize; 5076 *coveredPoints = meet[i]; 5077 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5078 PetscCall(PetscFree(closures)); 5079 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5080 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5081 PetscFunctionReturn(PETSC_SUCCESS); 5082 } 5083 5084 /*@ 5085 DMPlexEqual - Determine if two `DM` have the same topology 5086 5087 Not Collective 5088 5089 Input Parameters: 5090 + dmA - A `DMPLEX` object 5091 - dmB - A `DMPLEX` object 5092 5093 Output Parameter: 5094 . equal - `PETSC_TRUE` if the topologies are identical 5095 5096 Level: intermediate 5097 5098 Note: 5099 We are not solving graph isomorphism, so we do not permute. 5100 5101 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5102 @*/ 5103 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5104 { 5105 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5106 5107 PetscFunctionBegin; 5108 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5109 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5110 PetscAssertPointer(equal, 3); 5111 5112 *equal = PETSC_FALSE; 5113 PetscCall(DMPlexGetDepth(dmA, &depth)); 5114 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5115 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5116 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5117 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5118 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5119 for (p = pStart; p < pEnd; ++p) { 5120 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5121 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5122 5123 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5124 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5125 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5126 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5127 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5128 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5129 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5130 for (c = 0; c < coneSize; ++c) { 5131 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5132 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5133 } 5134 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5135 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5136 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5137 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5138 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5139 for (s = 0; s < supportSize; ++s) { 5140 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5141 } 5142 } 5143 *equal = PETSC_TRUE; 5144 PetscFunctionReturn(PETSC_SUCCESS); 5145 } 5146 5147 /*@ 5148 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5149 5150 Not Collective 5151 5152 Input Parameters: 5153 + dm - The `DMPLEX` 5154 . cellDim - The cell dimension 5155 - numCorners - The number of vertices on a cell 5156 5157 Output Parameter: 5158 . numFaceVertices - The number of vertices on a face 5159 5160 Level: developer 5161 5162 Note: 5163 Of course this can only work for a restricted set of symmetric shapes 5164 5165 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5166 @*/ 5167 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5168 { 5169 MPI_Comm comm; 5170 5171 PetscFunctionBegin; 5172 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5173 PetscAssertPointer(numFaceVertices, 4); 5174 switch (cellDim) { 5175 case 0: 5176 *numFaceVertices = 0; 5177 break; 5178 case 1: 5179 *numFaceVertices = 1; 5180 break; 5181 case 2: 5182 switch (numCorners) { 5183 case 3: /* triangle */ 5184 *numFaceVertices = 2; /* Edge has 2 vertices */ 5185 break; 5186 case 4: /* quadrilateral */ 5187 *numFaceVertices = 2; /* Edge has 2 vertices */ 5188 break; 5189 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5190 *numFaceVertices = 3; /* Edge has 3 vertices */ 5191 break; 5192 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5193 *numFaceVertices = 3; /* Edge has 3 vertices */ 5194 break; 5195 default: 5196 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5197 } 5198 break; 5199 case 3: 5200 switch (numCorners) { 5201 case 4: /* tetradehdron */ 5202 *numFaceVertices = 3; /* Face has 3 vertices */ 5203 break; 5204 case 6: /* tet cohesive cells */ 5205 *numFaceVertices = 4; /* Face has 4 vertices */ 5206 break; 5207 case 8: /* hexahedron */ 5208 *numFaceVertices = 4; /* Face has 4 vertices */ 5209 break; 5210 case 9: /* tet cohesive Lagrange cells */ 5211 *numFaceVertices = 6; /* Face has 6 vertices */ 5212 break; 5213 case 10: /* quadratic tetrahedron */ 5214 *numFaceVertices = 6; /* Face has 6 vertices */ 5215 break; 5216 case 12: /* hex cohesive Lagrange cells */ 5217 *numFaceVertices = 6; /* Face has 6 vertices */ 5218 break; 5219 case 18: /* quadratic tet cohesive Lagrange cells */ 5220 *numFaceVertices = 6; /* Face has 6 vertices */ 5221 break; 5222 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5223 *numFaceVertices = 9; /* Face has 9 vertices */ 5224 break; 5225 default: 5226 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5227 } 5228 break; 5229 default: 5230 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5231 } 5232 PetscFunctionReturn(PETSC_SUCCESS); 5233 } 5234 5235 /*@ 5236 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5237 5238 Not Collective 5239 5240 Input Parameter: 5241 . dm - The `DMPLEX` object 5242 5243 Output Parameter: 5244 . depthLabel - The `DMLabel` recording point depth 5245 5246 Level: developer 5247 5248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5249 @*/ 5250 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5251 { 5252 PetscFunctionBegin; 5253 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5254 PetscAssertPointer(depthLabel, 2); 5255 *depthLabel = dm->depthLabel; 5256 PetscFunctionReturn(PETSC_SUCCESS); 5257 } 5258 5259 /*@ 5260 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5261 5262 Not Collective 5263 5264 Input Parameter: 5265 . dm - The `DMPLEX` object 5266 5267 Output Parameter: 5268 . depth - The number of strata (breadth first levels) in the DAG 5269 5270 Level: developer 5271 5272 Notes: 5273 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5274 5275 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5276 5277 An empty mesh gives -1. 5278 5279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5280 @*/ 5281 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5282 { 5283 DM_Plex *mesh = (DM_Plex *)dm->data; 5284 DMLabel label; 5285 PetscInt d = -1; 5286 5287 PetscFunctionBegin; 5288 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5289 PetscAssertPointer(depth, 2); 5290 if (mesh->tr) { 5291 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5292 } else { 5293 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5294 // Allow missing depths 5295 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5296 *depth = d; 5297 } 5298 PetscFunctionReturn(PETSC_SUCCESS); 5299 } 5300 5301 /*@ 5302 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5303 5304 Not Collective 5305 5306 Input Parameters: 5307 + dm - The `DMPLEX` object 5308 - depth - The requested depth 5309 5310 Output Parameters: 5311 + start - The first point at this `depth` 5312 - end - One beyond the last point at this `depth` 5313 5314 Level: developer 5315 5316 Notes: 5317 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5318 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5319 higher dimension, e.g., "edges". 5320 5321 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5322 @*/ 5323 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5324 { 5325 DM_Plex *mesh = (DM_Plex *)dm->data; 5326 DMLabel label; 5327 PetscInt pStart, pEnd; 5328 5329 PetscFunctionBegin; 5330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5331 if (start) { 5332 PetscAssertPointer(start, 3); 5333 *start = 0; 5334 } 5335 if (end) { 5336 PetscAssertPointer(end, 4); 5337 *end = 0; 5338 } 5339 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5340 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5341 if (depth < 0) { 5342 if (start) *start = pStart; 5343 if (end) *end = pEnd; 5344 PetscFunctionReturn(PETSC_SUCCESS); 5345 } 5346 if (mesh->tr) { 5347 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5348 } else { 5349 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5350 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5351 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5352 } 5353 PetscFunctionReturn(PETSC_SUCCESS); 5354 } 5355 5356 /*@ 5357 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5358 5359 Not Collective 5360 5361 Input Parameters: 5362 + dm - The `DMPLEX` object 5363 - height - The requested height 5364 5365 Output Parameters: 5366 + start - The first point at this `height` 5367 - end - One beyond the last point at this `height` 5368 5369 Level: developer 5370 5371 Notes: 5372 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5373 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5374 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5375 5376 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5377 @*/ 5378 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5379 { 5380 DMLabel label; 5381 PetscInt depth, pStart, pEnd; 5382 5383 PetscFunctionBegin; 5384 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5385 if (start) { 5386 PetscAssertPointer(start, 3); 5387 *start = 0; 5388 } 5389 if (end) { 5390 PetscAssertPointer(end, 4); 5391 *end = 0; 5392 } 5393 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5394 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5395 if (height < 0) { 5396 if (start) *start = pStart; 5397 if (end) *end = pEnd; 5398 PetscFunctionReturn(PETSC_SUCCESS); 5399 } 5400 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5401 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5402 else PetscCall(DMGetDimension(dm, &depth)); 5403 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5404 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5405 PetscFunctionReturn(PETSC_SUCCESS); 5406 } 5407 5408 /*@ 5409 DMPlexGetPointDepth - Get the `depth` of a given point 5410 5411 Not Collective 5412 5413 Input Parameters: 5414 + dm - The `DMPLEX` object 5415 - point - The point 5416 5417 Output Parameter: 5418 . depth - The depth of the `point` 5419 5420 Level: intermediate 5421 5422 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5423 @*/ 5424 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5425 { 5426 PetscFunctionBegin; 5427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5428 PetscAssertPointer(depth, 3); 5429 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5430 PetscFunctionReturn(PETSC_SUCCESS); 5431 } 5432 5433 /*@ 5434 DMPlexGetPointHeight - Get the `height` of a given point 5435 5436 Not Collective 5437 5438 Input Parameters: 5439 + dm - The `DMPLEX` object 5440 - point - The point 5441 5442 Output Parameter: 5443 . height - The height of the `point` 5444 5445 Level: intermediate 5446 5447 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5448 @*/ 5449 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5450 { 5451 PetscInt n, pDepth; 5452 5453 PetscFunctionBegin; 5454 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5455 PetscAssertPointer(height, 3); 5456 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5457 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5458 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5459 PetscFunctionReturn(PETSC_SUCCESS); 5460 } 5461 5462 /*@ 5463 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5464 5465 Not Collective 5466 5467 Input Parameter: 5468 . dm - The `DMPLEX` object 5469 5470 Output Parameter: 5471 . celltypeLabel - The `DMLabel` recording cell polytope type 5472 5473 Level: developer 5474 5475 Note: 5476 This function will trigger automatica computation of cell types. This can be disabled by calling 5477 `DMCreateLabel`(dm, "celltype") beforehand. 5478 5479 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5480 @*/ 5481 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5482 { 5483 PetscFunctionBegin; 5484 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5485 PetscAssertPointer(celltypeLabel, 2); 5486 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5487 *celltypeLabel = dm->celltypeLabel; 5488 PetscFunctionReturn(PETSC_SUCCESS); 5489 } 5490 5491 /*@ 5492 DMPlexGetCellType - Get the polytope type of a given cell 5493 5494 Not Collective 5495 5496 Input Parameters: 5497 + dm - The `DMPLEX` object 5498 - cell - The cell 5499 5500 Output Parameter: 5501 . celltype - The polytope type of the cell 5502 5503 Level: intermediate 5504 5505 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5506 @*/ 5507 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5508 { 5509 DM_Plex *mesh = (DM_Plex *)dm->data; 5510 DMLabel label; 5511 PetscInt ct; 5512 5513 PetscFunctionBegin; 5514 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5515 PetscAssertPointer(celltype, 3); 5516 if (mesh->tr) { 5517 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5518 } else { 5519 PetscInt pStart, pEnd; 5520 5521 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5522 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5523 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5524 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5525 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5526 for (PetscInt p = pStart; p < pEnd; p++) { 5527 PetscCall(DMLabelGetValue(label, p, &ct)); 5528 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5529 } 5530 } 5531 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5532 if (PetscDefined(USE_DEBUG)) { 5533 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5534 PetscCall(DMLabelGetValue(label, cell, &ct)); 5535 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5536 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5537 } 5538 } 5539 PetscFunctionReturn(PETSC_SUCCESS); 5540 } 5541 5542 /*@ 5543 DMPlexSetCellType - Set the polytope type of a given cell 5544 5545 Not Collective 5546 5547 Input Parameters: 5548 + dm - The `DMPLEX` object 5549 . cell - The cell 5550 - celltype - The polytope type of the cell 5551 5552 Level: advanced 5553 5554 Note: 5555 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5556 is executed. This function will override the computed type. However, if automatic classification will not succeed 5557 and a user wants to manually specify all types, the classification must be disabled by calling 5558 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5559 5560 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5561 @*/ 5562 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5563 { 5564 DM_Plex *mesh = (DM_Plex *)dm->data; 5565 DMLabel label; 5566 PetscInt pStart, pEnd; 5567 5568 PetscFunctionBegin; 5569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5570 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5571 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5572 PetscCall(DMLabelSetValue(label, cell, celltype)); 5573 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5574 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5575 PetscFunctionReturn(PETSC_SUCCESS); 5576 } 5577 5578 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5579 { 5580 PetscSection section; 5581 PetscInt maxHeight; 5582 const char *prefix; 5583 5584 PetscFunctionBegin; 5585 PetscCall(DMClone(dm, cdm)); 5586 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5587 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5588 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5589 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5590 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5591 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5592 PetscCall(DMSetLocalSection(*cdm, section)); 5593 PetscCall(PetscSectionDestroy(§ion)); 5594 5595 PetscCall(DMSetNumFields(*cdm, 1)); 5596 PetscCall(DMCreateDS(*cdm)); 5597 (*cdm)->cloneOpts = PETSC_TRUE; 5598 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5599 PetscFunctionReturn(PETSC_SUCCESS); 5600 } 5601 5602 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5603 { 5604 Vec coordsLocal, cellCoordsLocal; 5605 DM coordsDM, cellCoordsDM; 5606 5607 PetscFunctionBegin; 5608 *field = NULL; 5609 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5610 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5611 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5612 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5613 if (coordsLocal && coordsDM) { 5614 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5615 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5616 } 5617 PetscFunctionReturn(PETSC_SUCCESS); 5618 } 5619 5620 /*@ 5621 DMPlexGetConeSection - Return a section which describes the layout of cone data 5622 5623 Not Collective 5624 5625 Input Parameter: 5626 . dm - The `DMPLEX` object 5627 5628 Output Parameter: 5629 . section - The `PetscSection` object 5630 5631 Level: developer 5632 5633 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5634 @*/ 5635 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5636 { 5637 DM_Plex *mesh = (DM_Plex *)dm->data; 5638 5639 PetscFunctionBegin; 5640 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5641 if (section) *section = mesh->coneSection; 5642 PetscFunctionReturn(PETSC_SUCCESS); 5643 } 5644 5645 /*@ 5646 DMPlexGetSupportSection - Return a section which describes the layout of support data 5647 5648 Not Collective 5649 5650 Input Parameter: 5651 . dm - The `DMPLEX` object 5652 5653 Output Parameter: 5654 . section - The `PetscSection` object 5655 5656 Level: developer 5657 5658 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5659 @*/ 5660 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5661 { 5662 DM_Plex *mesh = (DM_Plex *)dm->data; 5663 5664 PetscFunctionBegin; 5665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5666 if (section) *section = mesh->supportSection; 5667 PetscFunctionReturn(PETSC_SUCCESS); 5668 } 5669 5670 /*@C 5671 DMPlexGetCones - Return cone data 5672 5673 Not Collective 5674 5675 Input Parameter: 5676 . dm - The `DMPLEX` object 5677 5678 Output Parameter: 5679 . cones - The cone for each point 5680 5681 Level: developer 5682 5683 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5684 @*/ 5685 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5686 { 5687 DM_Plex *mesh = (DM_Plex *)dm->data; 5688 5689 PetscFunctionBegin; 5690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5691 if (cones) *cones = mesh->cones; 5692 PetscFunctionReturn(PETSC_SUCCESS); 5693 } 5694 5695 /*@C 5696 DMPlexGetConeOrientations - Return cone orientation data 5697 5698 Not Collective 5699 5700 Input Parameter: 5701 . dm - The `DMPLEX` object 5702 5703 Output Parameter: 5704 . coneOrientations - The array of cone orientations for all points 5705 5706 Level: developer 5707 5708 Notes: 5709 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5710 5711 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5712 5713 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5714 @*/ 5715 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5716 { 5717 DM_Plex *mesh = (DM_Plex *)dm->data; 5718 5719 PetscFunctionBegin; 5720 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5721 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5722 PetscFunctionReturn(PETSC_SUCCESS); 5723 } 5724 5725 /******************************** FEM Support **********************************/ 5726 5727 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5728 { 5729 PetscInt depth; 5730 5731 PetscFunctionBegin; 5732 PetscCall(DMPlexGetDepth(plex, &depth)); 5733 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5734 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5735 PetscFunctionReturn(PETSC_SUCCESS); 5736 } 5737 5738 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5739 { 5740 PetscInt depth; 5741 5742 PetscFunctionBegin; 5743 PetscCall(DMPlexGetDepth(plex, &depth)); 5744 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5745 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5746 PetscFunctionReturn(PETSC_SUCCESS); 5747 } 5748 5749 /* 5750 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5751 representing a line in the section. 5752 */ 5753 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5754 { 5755 PetscObject obj; 5756 PetscClassId id; 5757 PetscFE fe = NULL; 5758 5759 PetscFunctionBeginHot; 5760 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5761 PetscCall(DMGetField(dm, field, NULL, &obj)); 5762 PetscCall(PetscObjectGetClassId(obj, &id)); 5763 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5764 5765 if (!fe) { 5766 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5767 /* An order k SEM disc has k-1 dofs on an edge */ 5768 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5769 *k = *k / *Nc + 1; 5770 } else { 5771 PetscInt dual_space_size, dim; 5772 PetscDualSpace dsp; 5773 5774 PetscCall(DMGetDimension(dm, &dim)); 5775 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5776 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5777 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5778 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5779 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5780 } 5781 PetscFunctionReturn(PETSC_SUCCESS); 5782 } 5783 5784 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5785 { 5786 PetscFunctionBeginHot; 5787 if (tensor) { 5788 *dof = PetscPowInt(k + 1, dim); 5789 } else { 5790 switch (dim) { 5791 case 1: 5792 *dof = k + 1; 5793 break; 5794 case 2: 5795 *dof = ((k + 1) * (k + 2)) / 2; 5796 break; 5797 case 3: 5798 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5799 break; 5800 default: 5801 *dof = 0; 5802 } 5803 } 5804 PetscFunctionReturn(PETSC_SUCCESS); 5805 } 5806 5807 /*@ 5808 5809 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5810 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5811 section provided (or the section of the `DM`). 5812 5813 Input Parameters: 5814 + dm - The `DM` 5815 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5816 - section - The `PetscSection` to reorder, or `NULL` for the default section 5817 5818 Example: 5819 A typical interpolated single-quad mesh might order points as 5820 .vb 5821 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5822 5823 v4 -- e6 -- v3 5824 | | 5825 e7 c0 e8 5826 | | 5827 v1 -- e5 -- v2 5828 .ve 5829 5830 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5831 dofs in the order of points, e.g., 5832 .vb 5833 c0 -> [0,1,2,3] 5834 v1 -> [4] 5835 ... 5836 e5 -> [8, 9] 5837 .ve 5838 5839 which corresponds to the dofs 5840 .vb 5841 6 10 11 7 5842 13 2 3 15 5843 12 0 1 14 5844 4 8 9 5 5845 .ve 5846 5847 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5848 .vb 5849 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5850 .ve 5851 5852 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5853 .vb 5854 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5855 .ve 5856 5857 Level: developer 5858 5859 Notes: 5860 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5861 degree of the basis. 5862 5863 This is required to run with libCEED. 5864 5865 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5866 @*/ 5867 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5868 { 5869 DMLabel label; 5870 PetscInt dim, depth = -1, eStart = -1, Nf; 5871 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5872 5873 PetscFunctionBegin; 5874 PetscCall(DMGetDimension(dm, &dim)); 5875 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5876 if (point < 0) { 5877 PetscInt sStart, sEnd; 5878 5879 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5880 point = sEnd - sStart ? sStart : point; 5881 } 5882 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5883 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5884 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5885 if (depth == 1) { 5886 eStart = point; 5887 } else if (depth == dim) { 5888 const PetscInt *cone; 5889 5890 PetscCall(DMPlexGetCone(dm, point, &cone)); 5891 if (dim == 2) eStart = cone[0]; 5892 else if (dim == 3) { 5893 const PetscInt *cone2; 5894 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5895 eStart = cone2[0]; 5896 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5897 } else PetscCheck(depth < 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5898 5899 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5900 for (PetscInt d = 1; d <= dim; d++) { 5901 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5902 PetscInt *perm; 5903 5904 for (f = 0; f < Nf; ++f) { 5905 PetscInt dof; 5906 5907 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5908 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5909 if (!continuous && d < dim) continue; 5910 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5911 size += dof * Nc; 5912 } 5913 PetscCall(PetscMalloc1(size, &perm)); 5914 for (f = 0; f < Nf; ++f) { 5915 switch (d) { 5916 case 1: 5917 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5918 if (!continuous && d < dim) continue; 5919 /* 5920 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5921 We want [ vtx0; edge of length k-1; vtx1 ] 5922 */ 5923 if (continuous) { 5924 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5925 for (i = 0; i < k - 1; i++) 5926 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5927 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5928 foffset = offset; 5929 } else { 5930 PetscInt dof; 5931 5932 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5933 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5934 foffset = offset; 5935 } 5936 break; 5937 case 2: 5938 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5939 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5940 if (!continuous && d < dim) continue; 5941 /* The SEM order is 5942 5943 v_lb, {e_b}, v_rb, 5944 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5945 v_lt, reverse {e_t}, v_rt 5946 */ 5947 if (continuous) { 5948 const PetscInt of = 0; 5949 const PetscInt oeb = of + PetscSqr(k - 1); 5950 const PetscInt oer = oeb + (k - 1); 5951 const PetscInt oet = oer + (k - 1); 5952 const PetscInt oel = oet + (k - 1); 5953 const PetscInt ovlb = oel + (k - 1); 5954 const PetscInt ovrb = ovlb + 1; 5955 const PetscInt ovrt = ovrb + 1; 5956 const PetscInt ovlt = ovrt + 1; 5957 PetscInt o; 5958 5959 /* bottom */ 5960 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5961 for (o = oeb; o < oer; ++o) 5962 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5963 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5964 /* middle */ 5965 for (i = 0; i < k - 1; ++i) { 5966 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5967 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5968 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5969 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5970 } 5971 /* top */ 5972 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5973 for (o = oel - 1; o >= oet; --o) 5974 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5975 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5976 foffset = offset; 5977 } else { 5978 PetscInt dof; 5979 5980 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5981 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5982 foffset = offset; 5983 } 5984 break; 5985 case 3: 5986 /* The original hex closure is 5987 5988 {c, 5989 f_b, f_t, f_f, f_b, f_r, f_l, 5990 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5991 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5992 */ 5993 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5994 if (!continuous && d < dim) continue; 5995 /* The SEM order is 5996 Bottom Slice 5997 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5998 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5999 v_blb, {e_bb}, v_brb, 6000 6001 Middle Slice (j) 6002 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6003 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6004 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6005 6006 Top Slice 6007 v_tlf, {e_tf}, v_trf, 6008 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6009 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6010 */ 6011 if (continuous) { 6012 const PetscInt oc = 0; 6013 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6014 const PetscInt oft = ofb + PetscSqr(k - 1); 6015 const PetscInt off = oft + PetscSqr(k - 1); 6016 const PetscInt ofk = off + PetscSqr(k - 1); 6017 const PetscInt ofr = ofk + PetscSqr(k - 1); 6018 const PetscInt ofl = ofr + PetscSqr(k - 1); 6019 const PetscInt oebl = ofl + PetscSqr(k - 1); 6020 const PetscInt oebb = oebl + (k - 1); 6021 const PetscInt oebr = oebb + (k - 1); 6022 const PetscInt oebf = oebr + (k - 1); 6023 const PetscInt oetf = oebf + (k - 1); 6024 const PetscInt oetr = oetf + (k - 1); 6025 const PetscInt oetb = oetr + (k - 1); 6026 const PetscInt oetl = oetb + (k - 1); 6027 const PetscInt oerf = oetl + (k - 1); 6028 const PetscInt oelf = oerf + (k - 1); 6029 const PetscInt oelb = oelf + (k - 1); 6030 const PetscInt oerb = oelb + (k - 1); 6031 const PetscInt ovblf = oerb + (k - 1); 6032 const PetscInt ovblb = ovblf + 1; 6033 const PetscInt ovbrb = ovblb + 1; 6034 const PetscInt ovbrf = ovbrb + 1; 6035 const PetscInt ovtlf = ovbrf + 1; 6036 const PetscInt ovtrf = ovtlf + 1; 6037 const PetscInt ovtrb = ovtrf + 1; 6038 const PetscInt ovtlb = ovtrb + 1; 6039 PetscInt o, n; 6040 6041 /* Bottom Slice */ 6042 /* bottom */ 6043 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6044 for (o = oetf - 1; o >= oebf; --o) 6045 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6046 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6047 /* middle */ 6048 for (i = 0; i < k - 1; ++i) { 6049 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6050 for (n = 0; n < k - 1; ++n) { 6051 o = ofb + n * (k - 1) + i; 6052 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6053 } 6054 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6055 } 6056 /* top */ 6057 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6058 for (o = oebb; o < oebr; ++o) 6059 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6060 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6061 6062 /* Middle Slice */ 6063 for (j = 0; j < k - 1; ++j) { 6064 /* bottom */ 6065 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6066 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6067 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6068 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6069 /* middle */ 6070 for (i = 0; i < k - 1; ++i) { 6071 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6072 for (n = 0; n < k - 1; ++n) 6073 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6074 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6075 } 6076 /* top */ 6077 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6078 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6079 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6080 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6081 } 6082 6083 /* Top Slice */ 6084 /* bottom */ 6085 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6086 for (o = oetf; o < oetr; ++o) 6087 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6088 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6089 /* middle */ 6090 for (i = 0; i < k - 1; ++i) { 6091 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6092 for (n = 0; n < k - 1; ++n) 6093 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6094 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6095 } 6096 /* top */ 6097 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6098 for (o = oetl - 1; o >= oetb; --o) 6099 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6100 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6101 6102 foffset = offset; 6103 } else { 6104 PetscInt dof; 6105 6106 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6107 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6108 foffset = offset; 6109 } 6110 break; 6111 default: 6112 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6113 } 6114 } 6115 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6116 /* Check permutation */ 6117 { 6118 PetscInt *check; 6119 6120 PetscCall(PetscMalloc1(size, &check)); 6121 for (i = 0; i < size; ++i) { 6122 check[i] = -1; 6123 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6124 } 6125 for (i = 0; i < size; ++i) check[perm[i]] = i; 6126 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6127 PetscCall(PetscFree(check)); 6128 } 6129 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6130 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6131 PetscInt *loc_perm; 6132 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6133 for (PetscInt i = 0; i < size; i++) { 6134 loc_perm[i] = perm[i]; 6135 loc_perm[size + i] = size + perm[i]; 6136 } 6137 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6138 } 6139 } 6140 PetscFunctionReturn(PETSC_SUCCESS); 6141 } 6142 6143 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6144 { 6145 PetscDS prob; 6146 PetscInt depth, Nf, h; 6147 DMLabel label; 6148 6149 PetscFunctionBeginHot; 6150 PetscCall(DMGetDS(dm, &prob)); 6151 Nf = prob->Nf; 6152 label = dm->depthLabel; 6153 *dspace = NULL; 6154 if (field < Nf) { 6155 PetscObject disc = prob->disc[field]; 6156 6157 if (disc->classid == PETSCFE_CLASSID) { 6158 PetscDualSpace dsp; 6159 6160 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6161 PetscCall(DMLabelGetNumValues(label, &depth)); 6162 PetscCall(DMLabelGetValue(label, point, &h)); 6163 h = depth - 1 - h; 6164 if (h) { 6165 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6166 } else { 6167 *dspace = dsp; 6168 } 6169 } 6170 } 6171 PetscFunctionReturn(PETSC_SUCCESS); 6172 } 6173 6174 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6175 { 6176 PetscScalar *array; 6177 const PetscScalar *vArray; 6178 const PetscInt *cone, *coneO; 6179 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6180 6181 PetscFunctionBeginHot; 6182 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6183 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6184 PetscCall(DMPlexGetCone(dm, point, &cone)); 6185 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6186 if (!values || !*values) { 6187 if ((point >= pStart) && (point < pEnd)) { 6188 PetscInt dof; 6189 6190 PetscCall(PetscSectionGetDof(section, point, &dof)); 6191 size += dof; 6192 } 6193 for (p = 0; p < numPoints; ++p) { 6194 const PetscInt cp = cone[p]; 6195 PetscInt dof; 6196 6197 if ((cp < pStart) || (cp >= pEnd)) continue; 6198 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6199 size += dof; 6200 } 6201 if (!values) { 6202 if (csize) *csize = size; 6203 PetscFunctionReturn(PETSC_SUCCESS); 6204 } 6205 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6206 } else { 6207 array = *values; 6208 } 6209 size = 0; 6210 PetscCall(VecGetArrayRead(v, &vArray)); 6211 if ((point >= pStart) && (point < pEnd)) { 6212 PetscInt dof, off, d; 6213 const PetscScalar *varr; 6214 6215 PetscCall(PetscSectionGetDof(section, point, &dof)); 6216 PetscCall(PetscSectionGetOffset(section, point, &off)); 6217 varr = PetscSafePointerPlusOffset(vArray, off); 6218 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6219 size += dof; 6220 } 6221 for (p = 0; p < numPoints; ++p) { 6222 const PetscInt cp = cone[p]; 6223 PetscInt o = coneO[p]; 6224 PetscInt dof, off, d; 6225 const PetscScalar *varr; 6226 6227 if ((cp < pStart) || (cp >= pEnd)) continue; 6228 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6229 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6230 varr = PetscSafePointerPlusOffset(vArray, off); 6231 if (o >= 0) { 6232 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6233 } else { 6234 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6235 } 6236 size += dof; 6237 } 6238 PetscCall(VecRestoreArrayRead(v, &vArray)); 6239 if (!*values) { 6240 if (csize) *csize = size; 6241 *values = array; 6242 } else { 6243 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6244 *csize = size; 6245 } 6246 PetscFunctionReturn(PETSC_SUCCESS); 6247 } 6248 6249 /* Compress out points not in the section */ 6250 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6251 { 6252 const PetscInt np = *numPoints; 6253 PetscInt pStart, pEnd, p, q; 6254 6255 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6256 for (p = 0, q = 0; p < np; ++p) { 6257 const PetscInt r = points[p * 2]; 6258 if ((r >= pStart) && (r < pEnd)) { 6259 points[q * 2] = r; 6260 points[q * 2 + 1] = points[p * 2 + 1]; 6261 ++q; 6262 } 6263 } 6264 *numPoints = q; 6265 return PETSC_SUCCESS; 6266 } 6267 6268 /* Compressed closure does not apply closure permutation */ 6269 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6270 { 6271 const PetscInt *cla = NULL; 6272 PetscInt np, *pts = NULL; 6273 6274 PetscFunctionBeginHot; 6275 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6276 if (!ornt && *clPoints) { 6277 PetscInt dof, off; 6278 6279 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6280 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6281 PetscCall(ISGetIndices(*clPoints, &cla)); 6282 np = dof / 2; 6283 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6284 } else { 6285 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6286 PetscCall(CompressPoints_Private(section, &np, pts)); 6287 } 6288 *numPoints = np; 6289 *points = pts; 6290 *clp = cla; 6291 PetscFunctionReturn(PETSC_SUCCESS); 6292 } 6293 6294 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6295 { 6296 PetscFunctionBeginHot; 6297 if (!*clPoints) { 6298 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6299 } else { 6300 PetscCall(ISRestoreIndices(*clPoints, clp)); 6301 } 6302 *numPoints = 0; 6303 *points = NULL; 6304 *clSec = NULL; 6305 *clPoints = NULL; 6306 *clp = NULL; 6307 PetscFunctionReturn(PETSC_SUCCESS); 6308 } 6309 6310 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6311 { 6312 PetscInt offset = 0, p; 6313 const PetscInt **perms = NULL; 6314 const PetscScalar **flips = NULL; 6315 6316 PetscFunctionBeginHot; 6317 *size = 0; 6318 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6319 for (p = 0; p < numPoints; p++) { 6320 const PetscInt point = points[2 * p]; 6321 const PetscInt *perm = perms ? perms[p] : NULL; 6322 const PetscScalar *flip = flips ? flips[p] : NULL; 6323 PetscInt dof, off, d; 6324 const PetscScalar *varr; 6325 6326 PetscCall(PetscSectionGetDof(section, point, &dof)); 6327 PetscCall(PetscSectionGetOffset(section, point, &off)); 6328 varr = PetscSafePointerPlusOffset(vArray, off); 6329 if (clperm) { 6330 if (perm) { 6331 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6332 } else { 6333 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6334 } 6335 if (flip) { 6336 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6337 } 6338 } else { 6339 if (perm) { 6340 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6341 } else { 6342 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6343 } 6344 if (flip) { 6345 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6346 } 6347 } 6348 offset += dof; 6349 } 6350 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6351 *size = offset; 6352 PetscFunctionReturn(PETSC_SUCCESS); 6353 } 6354 6355 static inline PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6356 { 6357 PetscInt offset = 0, f; 6358 6359 PetscFunctionBeginHot; 6360 *size = 0; 6361 for (f = 0; f < numFields; ++f) { 6362 PetscInt p; 6363 const PetscInt **perms = NULL; 6364 const PetscScalar **flips = NULL; 6365 6366 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6367 for (p = 0; p < numPoints; p++) { 6368 const PetscInt point = points[2 * p]; 6369 PetscInt fdof, foff, b; 6370 const PetscScalar *varr; 6371 const PetscInt *perm = perms ? perms[p] : NULL; 6372 const PetscScalar *flip = flips ? flips[p] : NULL; 6373 6374 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6375 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6376 varr = &vArray[foff]; 6377 if (clperm) { 6378 if (perm) { 6379 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6380 } else { 6381 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6382 } 6383 if (flip) { 6384 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6385 } 6386 } else { 6387 if (perm) { 6388 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6389 } else { 6390 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6391 } 6392 if (flip) { 6393 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6394 } 6395 } 6396 offset += fdof; 6397 } 6398 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6399 } 6400 *size = offset; 6401 PetscFunctionReturn(PETSC_SUCCESS); 6402 } 6403 6404 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6405 { 6406 PetscSection clSection; 6407 IS clPoints; 6408 PetscInt *points = NULL; 6409 const PetscInt *clp, *perm = NULL; 6410 PetscInt depth, numFields, numPoints, asize; 6411 6412 PetscFunctionBeginHot; 6413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6414 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6415 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6416 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6417 PetscCall(DMPlexGetDepth(dm, &depth)); 6418 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6419 if (depth == 1 && numFields < 2) { 6420 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6421 PetscFunctionReturn(PETSC_SUCCESS); 6422 } 6423 /* Get points */ 6424 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6425 /* Get sizes */ 6426 asize = 0; 6427 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6428 PetscInt dof; 6429 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6430 asize += dof; 6431 } 6432 if (values) { 6433 const PetscScalar *vArray; 6434 PetscInt size; 6435 6436 if (*values) { 6437 PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 6438 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6439 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6440 PetscCall(VecGetArrayRead(v, &vArray)); 6441 /* Get values */ 6442 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6443 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6444 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6445 /* Cleanup array */ 6446 PetscCall(VecRestoreArrayRead(v, &vArray)); 6447 } 6448 if (csize) *csize = asize; 6449 /* Cleanup points */ 6450 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6451 PetscFunctionReturn(PETSC_SUCCESS); 6452 } 6453 6454 /*@C 6455 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6456 6457 Not collective 6458 6459 Input Parameters: 6460 + dm - The `DM` 6461 . section - The section describing the layout in `v`, or `NULL` to use the default section 6462 . v - The local vector 6463 - point - The point in the `DM` 6464 6465 Input/Output Parameters: 6466 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6467 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6468 if the user provided `NULL`, it is a borrowed array and should not be freed 6469 6470 Level: intermediate 6471 6472 Notes: 6473 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6474 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6475 assembly function, and a user may already have allocated storage for this operation. 6476 6477 A typical use could be 6478 .vb 6479 values = NULL; 6480 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6481 for (cl = 0; cl < clSize; ++cl) { 6482 <Compute on closure> 6483 } 6484 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6485 .ve 6486 or 6487 .vb 6488 PetscMalloc1(clMaxSize, &values); 6489 for (p = pStart; p < pEnd; ++p) { 6490 clSize = clMaxSize; 6491 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6492 for (cl = 0; cl < clSize; ++cl) { 6493 <Compute on closure> 6494 } 6495 } 6496 PetscFree(values); 6497 .ve 6498 6499 Fortran Notes: 6500 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6501 6502 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6503 @*/ 6504 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6505 { 6506 PetscFunctionBeginHot; 6507 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6508 PetscFunctionReturn(PETSC_SUCCESS); 6509 } 6510 6511 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6512 { 6513 DMLabel depthLabel; 6514 PetscSection clSection; 6515 IS clPoints; 6516 PetscScalar *array; 6517 const PetscScalar *vArray; 6518 PetscInt *points = NULL; 6519 const PetscInt *clp, *perm = NULL; 6520 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6521 6522 PetscFunctionBeginHot; 6523 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6524 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6525 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6526 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6527 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6528 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6529 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6530 if (mdepth == 1 && numFields < 2) { 6531 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6532 PetscFunctionReturn(PETSC_SUCCESS); 6533 } 6534 /* Get points */ 6535 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6536 for (clsize = 0, p = 0; p < Np; p++) { 6537 PetscInt dof; 6538 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6539 clsize += dof; 6540 } 6541 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6542 /* Filter points */ 6543 for (p = 0; p < numPoints * 2; p += 2) { 6544 PetscInt dep; 6545 6546 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6547 if (dep != depth) continue; 6548 points[Np * 2 + 0] = points[p]; 6549 points[Np * 2 + 1] = points[p + 1]; 6550 ++Np; 6551 } 6552 /* Get array */ 6553 if (!values || !*values) { 6554 PetscInt asize = 0, dof; 6555 6556 for (p = 0; p < Np * 2; p += 2) { 6557 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6558 asize += dof; 6559 } 6560 if (!values) { 6561 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6562 if (csize) *csize = asize; 6563 PetscFunctionReturn(PETSC_SUCCESS); 6564 } 6565 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6566 } else { 6567 array = *values; 6568 } 6569 PetscCall(VecGetArrayRead(v, &vArray)); 6570 /* Get values */ 6571 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6572 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6573 /* Cleanup points */ 6574 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6575 /* Cleanup array */ 6576 PetscCall(VecRestoreArrayRead(v, &vArray)); 6577 if (!*values) { 6578 if (csize) *csize = size; 6579 *values = array; 6580 } else { 6581 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6582 *csize = size; 6583 } 6584 PetscFunctionReturn(PETSC_SUCCESS); 6585 } 6586 6587 /*@C 6588 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6589 6590 Not collective 6591 6592 Input Parameters: 6593 + dm - The `DM` 6594 . section - The section describing the layout in `v`, or `NULL` to use the default section 6595 . v - The local vector 6596 . point - The point in the `DM` 6597 . csize - The number of values in the closure, or `NULL` 6598 - values - The array of values, which is a borrowed array and should not be freed 6599 6600 Level: intermediate 6601 6602 Note: 6603 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6604 6605 Fortran Notes: 6606 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6607 6608 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6609 @*/ 6610 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6611 { 6612 PetscInt size = 0; 6613 6614 PetscFunctionBegin; 6615 /* Should work without recalculating size */ 6616 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6617 *values = NULL; 6618 PetscFunctionReturn(PETSC_SUCCESS); 6619 } 6620 6621 static inline void add(PetscScalar *x, PetscScalar y) 6622 { 6623 *x += y; 6624 } 6625 static inline void insert(PetscScalar *x, PetscScalar y) 6626 { 6627 *x = y; 6628 } 6629 6630 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[]) 6631 { 6632 PetscInt cdof; /* The number of constraints on this point */ 6633 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6634 PetscScalar *a; 6635 PetscInt off, cind = 0, k; 6636 6637 PetscFunctionBegin; 6638 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6639 PetscCall(PetscSectionGetOffset(section, point, &off)); 6640 a = &array[off]; 6641 if (!cdof || setBC) { 6642 if (clperm) { 6643 if (perm) { 6644 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6645 } else { 6646 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6647 } 6648 } else { 6649 if (perm) { 6650 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6651 } else { 6652 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6653 } 6654 } 6655 } else { 6656 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6657 if (clperm) { 6658 if (perm) { 6659 for (k = 0; k < dof; ++k) { 6660 if ((cind < cdof) && (k == cdofs[cind])) { 6661 ++cind; 6662 continue; 6663 } 6664 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6665 } 6666 } else { 6667 for (k = 0; k < dof; ++k) { 6668 if ((cind < cdof) && (k == cdofs[cind])) { 6669 ++cind; 6670 continue; 6671 } 6672 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6673 } 6674 } 6675 } else { 6676 if (perm) { 6677 for (k = 0; k < dof; ++k) { 6678 if ((cind < cdof) && (k == cdofs[cind])) { 6679 ++cind; 6680 continue; 6681 } 6682 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6683 } 6684 } else { 6685 for (k = 0; k < dof; ++k) { 6686 if ((cind < cdof) && (k == cdofs[cind])) { 6687 ++cind; 6688 continue; 6689 } 6690 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6691 } 6692 } 6693 } 6694 } 6695 PetscFunctionReturn(PETSC_SUCCESS); 6696 } 6697 6698 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[]) 6699 { 6700 PetscInt cdof; /* The number of constraints on this point */ 6701 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6702 PetscScalar *a; 6703 PetscInt off, cind = 0, k; 6704 6705 PetscFunctionBegin; 6706 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6707 PetscCall(PetscSectionGetOffset(section, point, &off)); 6708 a = &array[off]; 6709 if (cdof) { 6710 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6711 if (clperm) { 6712 if (perm) { 6713 for (k = 0; k < dof; ++k) { 6714 if ((cind < cdof) && (k == cdofs[cind])) { 6715 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6716 cind++; 6717 } 6718 } 6719 } else { 6720 for (k = 0; k < dof; ++k) { 6721 if ((cind < cdof) && (k == cdofs[cind])) { 6722 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6723 cind++; 6724 } 6725 } 6726 } 6727 } else { 6728 if (perm) { 6729 for (k = 0; k < dof; ++k) { 6730 if ((cind < cdof) && (k == cdofs[cind])) { 6731 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6732 cind++; 6733 } 6734 } 6735 } else { 6736 for (k = 0; k < dof; ++k) { 6737 if ((cind < cdof) && (k == cdofs[cind])) { 6738 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6739 cind++; 6740 } 6741 } 6742 } 6743 } 6744 } 6745 PetscFunctionReturn(PETSC_SUCCESS); 6746 } 6747 6748 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[]) 6749 { 6750 PetscScalar *a; 6751 PetscInt fdof, foff, fcdof, foffset = *offset; 6752 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6753 PetscInt cind = 0, b; 6754 6755 PetscFunctionBegin; 6756 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6757 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6758 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6759 a = &array[foff]; 6760 if (!fcdof || setBC) { 6761 if (clperm) { 6762 if (perm) { 6763 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6764 } else { 6765 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6766 } 6767 } else { 6768 if (perm) { 6769 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6770 } else { 6771 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6772 } 6773 } 6774 } else { 6775 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6776 if (clperm) { 6777 if (perm) { 6778 for (b = 0; b < fdof; b++) { 6779 if ((cind < fcdof) && (b == fcdofs[cind])) { 6780 ++cind; 6781 continue; 6782 } 6783 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6784 } 6785 } else { 6786 for (b = 0; b < fdof; b++) { 6787 if ((cind < fcdof) && (b == fcdofs[cind])) { 6788 ++cind; 6789 continue; 6790 } 6791 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6792 } 6793 } 6794 } else { 6795 if (perm) { 6796 for (b = 0; b < fdof; b++) { 6797 if ((cind < fcdof) && (b == fcdofs[cind])) { 6798 ++cind; 6799 continue; 6800 } 6801 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6802 } 6803 } else { 6804 for (b = 0; b < fdof; b++) { 6805 if ((cind < fcdof) && (b == fcdofs[cind])) { 6806 ++cind; 6807 continue; 6808 } 6809 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6810 } 6811 } 6812 } 6813 } 6814 *offset += fdof; 6815 PetscFunctionReturn(PETSC_SUCCESS); 6816 } 6817 6818 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[]) 6819 { 6820 PetscScalar *a; 6821 PetscInt fdof, foff, fcdof, foffset = *offset; 6822 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6823 PetscInt Nc, cind = 0, ncind = 0, b; 6824 PetscBool ncSet, fcSet; 6825 6826 PetscFunctionBegin; 6827 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6828 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6829 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6830 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6831 a = &array[foff]; 6832 if (fcdof) { 6833 /* We just override fcdof and fcdofs with Ncc and comps */ 6834 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6835 if (clperm) { 6836 if (perm) { 6837 if (comps) { 6838 for (b = 0; b < fdof; b++) { 6839 ncSet = fcSet = PETSC_FALSE; 6840 if (b % Nc == comps[ncind]) { 6841 ncind = (ncind + 1) % Ncc; 6842 ncSet = PETSC_TRUE; 6843 } 6844 if ((cind < fcdof) && (b == fcdofs[cind])) { 6845 ++cind; 6846 fcSet = PETSC_TRUE; 6847 } 6848 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6849 } 6850 } else { 6851 for (b = 0; b < fdof; b++) { 6852 if ((cind < fcdof) && (b == fcdofs[cind])) { 6853 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6854 ++cind; 6855 } 6856 } 6857 } 6858 } else { 6859 if (comps) { 6860 for (b = 0; b < fdof; b++) { 6861 ncSet = fcSet = PETSC_FALSE; 6862 if (b % Nc == comps[ncind]) { 6863 ncind = (ncind + 1) % Ncc; 6864 ncSet = PETSC_TRUE; 6865 } 6866 if ((cind < fcdof) && (b == fcdofs[cind])) { 6867 ++cind; 6868 fcSet = PETSC_TRUE; 6869 } 6870 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6871 } 6872 } else { 6873 for (b = 0; b < fdof; b++) { 6874 if ((cind < fcdof) && (b == fcdofs[cind])) { 6875 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6876 ++cind; 6877 } 6878 } 6879 } 6880 } 6881 } else { 6882 if (perm) { 6883 if (comps) { 6884 for (b = 0; b < fdof; b++) { 6885 ncSet = fcSet = PETSC_FALSE; 6886 if (b % Nc == comps[ncind]) { 6887 ncind = (ncind + 1) % Ncc; 6888 ncSet = PETSC_TRUE; 6889 } 6890 if ((cind < fcdof) && (b == fcdofs[cind])) { 6891 ++cind; 6892 fcSet = PETSC_TRUE; 6893 } 6894 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6895 } 6896 } else { 6897 for (b = 0; b < fdof; b++) { 6898 if ((cind < fcdof) && (b == fcdofs[cind])) { 6899 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6900 ++cind; 6901 } 6902 } 6903 } 6904 } else { 6905 if (comps) { 6906 for (b = 0; b < fdof; b++) { 6907 ncSet = fcSet = PETSC_FALSE; 6908 if (b % Nc == comps[ncind]) { 6909 ncind = (ncind + 1) % Ncc; 6910 ncSet = PETSC_TRUE; 6911 } 6912 if ((cind < fcdof) && (b == fcdofs[cind])) { 6913 ++cind; 6914 fcSet = PETSC_TRUE; 6915 } 6916 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6917 } 6918 } else { 6919 for (b = 0; b < fdof; b++) { 6920 if ((cind < fcdof) && (b == fcdofs[cind])) { 6921 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6922 ++cind; 6923 } 6924 } 6925 } 6926 } 6927 } 6928 } 6929 *offset += fdof; 6930 PetscFunctionReturn(PETSC_SUCCESS); 6931 } 6932 6933 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6934 { 6935 PetscScalar *array; 6936 const PetscInt *cone, *coneO; 6937 PetscInt pStart, pEnd, p, numPoints, off, dof; 6938 6939 PetscFunctionBeginHot; 6940 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6941 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6942 PetscCall(DMPlexGetCone(dm, point, &cone)); 6943 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6944 PetscCall(VecGetArray(v, &array)); 6945 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6946 const PetscInt cp = !p ? point : cone[p - 1]; 6947 const PetscInt o = !p ? 0 : coneO[p - 1]; 6948 6949 if ((cp < pStart) || (cp >= pEnd)) { 6950 dof = 0; 6951 continue; 6952 } 6953 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6954 /* ADD_VALUES */ 6955 { 6956 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6957 PetscScalar *a; 6958 PetscInt cdof, coff, cind = 0, k; 6959 6960 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6961 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6962 a = &array[coff]; 6963 if (!cdof) { 6964 if (o >= 0) { 6965 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6966 } else { 6967 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6968 } 6969 } else { 6970 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6971 if (o >= 0) { 6972 for (k = 0; k < dof; ++k) { 6973 if ((cind < cdof) && (k == cdofs[cind])) { 6974 ++cind; 6975 continue; 6976 } 6977 a[k] += values[off + k]; 6978 } 6979 } else { 6980 for (k = 0; k < dof; ++k) { 6981 if ((cind < cdof) && (k == cdofs[cind])) { 6982 ++cind; 6983 continue; 6984 } 6985 a[k] += values[off + dof - k - 1]; 6986 } 6987 } 6988 } 6989 } 6990 } 6991 PetscCall(VecRestoreArray(v, &array)); 6992 PetscFunctionReturn(PETSC_SUCCESS); 6993 } 6994 6995 /*@C 6996 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6997 6998 Not collective 6999 7000 Input Parameters: 7001 + dm - The `DM` 7002 . section - The section describing the layout in `v`, or `NULL` to use the default section 7003 . v - The local vector 7004 . point - The point in the `DM` 7005 . values - The array of values 7006 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7007 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7008 7009 Level: intermediate 7010 7011 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7012 @*/ 7013 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7014 { 7015 PetscSection clSection; 7016 IS clPoints; 7017 PetscScalar *array; 7018 PetscInt *points = NULL; 7019 const PetscInt *clp, *clperm = NULL; 7020 PetscInt depth, numFields, numPoints, p, clsize; 7021 7022 PetscFunctionBeginHot; 7023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7024 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7025 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7026 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7027 PetscCall(DMPlexGetDepth(dm, &depth)); 7028 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7029 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7030 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7031 PetscFunctionReturn(PETSC_SUCCESS); 7032 } 7033 /* Get points */ 7034 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7035 for (clsize = 0, p = 0; p < numPoints; p++) { 7036 PetscInt dof; 7037 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7038 clsize += dof; 7039 } 7040 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7041 /* Get array */ 7042 PetscCall(VecGetArray(v, &array)); 7043 /* Get values */ 7044 if (numFields > 0) { 7045 PetscInt offset = 0, f; 7046 for (f = 0; f < numFields; ++f) { 7047 const PetscInt **perms = NULL; 7048 const PetscScalar **flips = NULL; 7049 7050 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7051 switch (mode) { 7052 case INSERT_VALUES: 7053 for (p = 0; p < numPoints; p++) { 7054 const PetscInt point = points[2 * p]; 7055 const PetscInt *perm = perms ? perms[p] : NULL; 7056 const PetscScalar *flip = flips ? flips[p] : NULL; 7057 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7058 } 7059 break; 7060 case INSERT_ALL_VALUES: 7061 for (p = 0; p < numPoints; p++) { 7062 const PetscInt point = points[2 * p]; 7063 const PetscInt *perm = perms ? perms[p] : NULL; 7064 const PetscScalar *flip = flips ? flips[p] : NULL; 7065 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7066 } 7067 break; 7068 case INSERT_BC_VALUES: 7069 for (p = 0; p < numPoints; p++) { 7070 const PetscInt point = points[2 * p]; 7071 const PetscInt *perm = perms ? perms[p] : NULL; 7072 const PetscScalar *flip = flips ? flips[p] : NULL; 7073 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7074 } 7075 break; 7076 case ADD_VALUES: 7077 for (p = 0; p < numPoints; p++) { 7078 const PetscInt point = points[2 * p]; 7079 const PetscInt *perm = perms ? perms[p] : NULL; 7080 const PetscScalar *flip = flips ? flips[p] : NULL; 7081 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7082 } 7083 break; 7084 case ADD_ALL_VALUES: 7085 for (p = 0; p < numPoints; p++) { 7086 const PetscInt point = points[2 * p]; 7087 const PetscInt *perm = perms ? perms[p] : NULL; 7088 const PetscScalar *flip = flips ? flips[p] : NULL; 7089 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7090 } 7091 break; 7092 case ADD_BC_VALUES: 7093 for (p = 0; p < numPoints; p++) { 7094 const PetscInt point = points[2 * p]; 7095 const PetscInt *perm = perms ? perms[p] : NULL; 7096 const PetscScalar *flip = flips ? flips[p] : NULL; 7097 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7098 } 7099 break; 7100 default: 7101 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7102 } 7103 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7104 } 7105 } else { 7106 PetscInt dof, off; 7107 const PetscInt **perms = NULL; 7108 const PetscScalar **flips = NULL; 7109 7110 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7111 switch (mode) { 7112 case INSERT_VALUES: 7113 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7114 const PetscInt point = points[2 * p]; 7115 const PetscInt *perm = perms ? perms[p] : NULL; 7116 const PetscScalar *flip = flips ? flips[p] : NULL; 7117 PetscCall(PetscSectionGetDof(section, point, &dof)); 7118 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7119 } 7120 break; 7121 case INSERT_ALL_VALUES: 7122 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7123 const PetscInt point = points[2 * p]; 7124 const PetscInt *perm = perms ? perms[p] : NULL; 7125 const PetscScalar *flip = flips ? flips[p] : NULL; 7126 PetscCall(PetscSectionGetDof(section, point, &dof)); 7127 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7128 } 7129 break; 7130 case INSERT_BC_VALUES: 7131 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7132 const PetscInt point = points[2 * p]; 7133 const PetscInt *perm = perms ? perms[p] : NULL; 7134 const PetscScalar *flip = flips ? flips[p] : NULL; 7135 PetscCall(PetscSectionGetDof(section, point, &dof)); 7136 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7137 } 7138 break; 7139 case ADD_VALUES: 7140 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7141 const PetscInt point = points[2 * p]; 7142 const PetscInt *perm = perms ? perms[p] : NULL; 7143 const PetscScalar *flip = flips ? flips[p] : NULL; 7144 PetscCall(PetscSectionGetDof(section, point, &dof)); 7145 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7146 } 7147 break; 7148 case ADD_ALL_VALUES: 7149 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7150 const PetscInt point = points[2 * p]; 7151 const PetscInt *perm = perms ? perms[p] : NULL; 7152 const PetscScalar *flip = flips ? flips[p] : NULL; 7153 PetscCall(PetscSectionGetDof(section, point, &dof)); 7154 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7155 } 7156 break; 7157 case ADD_BC_VALUES: 7158 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7159 const PetscInt point = points[2 * p]; 7160 const PetscInt *perm = perms ? perms[p] : NULL; 7161 const PetscScalar *flip = flips ? flips[p] : NULL; 7162 PetscCall(PetscSectionGetDof(section, point, &dof)); 7163 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7164 } 7165 break; 7166 default: 7167 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7168 } 7169 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7170 } 7171 /* Cleanup points */ 7172 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7173 /* Cleanup array */ 7174 PetscCall(VecRestoreArray(v, &array)); 7175 PetscFunctionReturn(PETSC_SUCCESS); 7176 } 7177 7178 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7179 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7180 { 7181 PetscFunctionBegin; 7182 *contains = PETSC_TRUE; 7183 if (label) { 7184 PetscInt fdof; 7185 7186 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7187 if (!*contains) { 7188 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7189 *offset += fdof; 7190 PetscFunctionReturn(PETSC_SUCCESS); 7191 } 7192 } 7193 PetscFunctionReturn(PETSC_SUCCESS); 7194 } 7195 7196 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7197 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) 7198 { 7199 PetscSection clSection; 7200 IS clPoints; 7201 PetscScalar *array; 7202 PetscInt *points = NULL; 7203 const PetscInt *clp; 7204 PetscInt numFields, numPoints, p; 7205 PetscInt offset = 0, f; 7206 7207 PetscFunctionBeginHot; 7208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7209 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7210 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7211 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7212 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7213 /* Get points */ 7214 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7215 /* Get array */ 7216 PetscCall(VecGetArray(v, &array)); 7217 /* Get values */ 7218 for (f = 0; f < numFields; ++f) { 7219 const PetscInt **perms = NULL; 7220 const PetscScalar **flips = NULL; 7221 PetscBool contains; 7222 7223 if (!fieldActive[f]) { 7224 for (p = 0; p < numPoints * 2; p += 2) { 7225 PetscInt fdof; 7226 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7227 offset += fdof; 7228 } 7229 continue; 7230 } 7231 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7232 switch (mode) { 7233 case INSERT_VALUES: 7234 for (p = 0; p < numPoints; p++) { 7235 const PetscInt point = points[2 * p]; 7236 const PetscInt *perm = perms ? perms[p] : NULL; 7237 const PetscScalar *flip = flips ? flips[p] : NULL; 7238 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7239 if (!contains) continue; 7240 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7241 } 7242 break; 7243 case INSERT_ALL_VALUES: 7244 for (p = 0; p < numPoints; p++) { 7245 const PetscInt point = points[2 * p]; 7246 const PetscInt *perm = perms ? perms[p] : NULL; 7247 const PetscScalar *flip = flips ? flips[p] : NULL; 7248 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7249 if (!contains) continue; 7250 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7251 } 7252 break; 7253 case INSERT_BC_VALUES: 7254 for (p = 0; p < numPoints; p++) { 7255 const PetscInt point = points[2 * p]; 7256 const PetscInt *perm = perms ? perms[p] : NULL; 7257 const PetscScalar *flip = flips ? flips[p] : NULL; 7258 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7259 if (!contains) continue; 7260 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7261 } 7262 break; 7263 case ADD_VALUES: 7264 for (p = 0; p < numPoints; p++) { 7265 const PetscInt point = points[2 * p]; 7266 const PetscInt *perm = perms ? perms[p] : NULL; 7267 const PetscScalar *flip = flips ? flips[p] : NULL; 7268 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7269 if (!contains) continue; 7270 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7271 } 7272 break; 7273 case ADD_ALL_VALUES: 7274 for (p = 0; p < numPoints; p++) { 7275 const PetscInt point = points[2 * p]; 7276 const PetscInt *perm = perms ? perms[p] : NULL; 7277 const PetscScalar *flip = flips ? flips[p] : NULL; 7278 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7279 if (!contains) continue; 7280 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7281 } 7282 break; 7283 default: 7284 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7285 } 7286 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7287 } 7288 /* Cleanup points */ 7289 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7290 /* Cleanup array */ 7291 PetscCall(VecRestoreArray(v, &array)); 7292 PetscFunctionReturn(PETSC_SUCCESS); 7293 } 7294 7295 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7296 { 7297 PetscMPIInt rank; 7298 PetscInt i, j; 7299 7300 PetscFunctionBegin; 7301 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7302 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7303 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7304 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7305 numCIndices = numCIndices ? numCIndices : numRIndices; 7306 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7307 for (i = 0; i < numRIndices; i++) { 7308 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7309 for (j = 0; j < numCIndices; j++) { 7310 #if defined(PETSC_USE_COMPLEX) 7311 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7312 #else 7313 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7314 #endif 7315 } 7316 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7317 } 7318 PetscFunctionReturn(PETSC_SUCCESS); 7319 } 7320 7321 /* 7322 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7323 7324 Input Parameters: 7325 + section - The section for this data layout 7326 . islocal - Is the section (and thus indices being requested) local or global? 7327 . point - The point contributing dofs with these indices 7328 . off - The global offset of this point 7329 . loff - The local offset of each field 7330 . setBC - The flag determining whether to include indices of boundary values 7331 . perm - A permutation of the dofs on this point, or NULL 7332 - indperm - A permutation of the entire indices array, or NULL 7333 7334 Output Parameter: 7335 . indices - Indices for dofs on this point 7336 7337 Level: developer 7338 7339 Note: The indices could be local or global, depending on the value of 'off'. 7340 */ 7341 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7342 { 7343 PetscInt dof; /* The number of unknowns on this point */ 7344 PetscInt cdof; /* The number of constraints on this point */ 7345 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7346 PetscInt cind = 0, k; 7347 7348 PetscFunctionBegin; 7349 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7350 PetscCall(PetscSectionGetDof(section, point, &dof)); 7351 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7352 if (!cdof || setBC) { 7353 for (k = 0; k < dof; ++k) { 7354 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7355 const PetscInt ind = indperm ? indperm[preind] : preind; 7356 7357 indices[ind] = off + k; 7358 } 7359 } else { 7360 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7361 for (k = 0; k < dof; ++k) { 7362 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7363 const PetscInt ind = indperm ? indperm[preind] : preind; 7364 7365 if ((cind < cdof) && (k == cdofs[cind])) { 7366 /* Insert check for returning constrained indices */ 7367 indices[ind] = -(off + k + 1); 7368 ++cind; 7369 } else { 7370 indices[ind] = off + k - (islocal ? 0 : cind); 7371 } 7372 } 7373 } 7374 *loff += dof; 7375 PetscFunctionReturn(PETSC_SUCCESS); 7376 } 7377 7378 /* 7379 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7380 7381 Input Parameters: 7382 + section - a section (global or local) 7383 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7384 . point - point within section 7385 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7386 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7387 . setBC - identify constrained (boundary condition) points via involution. 7388 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7389 . permsoff - offset 7390 - indperm - index permutation 7391 7392 Output Parameter: 7393 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7394 . indices - array to hold indices (as defined by section) of each dof associated with point 7395 7396 Notes: 7397 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7398 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7399 in the local vector. 7400 7401 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7402 significant). It is invalid to call with a global section and setBC=true. 7403 7404 Developer Note: 7405 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7406 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7407 offset could be obtained from the section instead of passing it explicitly as we do now. 7408 7409 Example: 7410 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7411 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7412 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7413 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. 7414 7415 Level: developer 7416 */ 7417 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[]) 7418 { 7419 PetscInt numFields, foff, f; 7420 7421 PetscFunctionBegin; 7422 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7423 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7424 for (f = 0, foff = 0; f < numFields; ++f) { 7425 PetscInt fdof, cfdof; 7426 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7427 PetscInt cind = 0, b; 7428 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7429 7430 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7431 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7432 if (!cfdof || setBC) { 7433 for (b = 0; b < fdof; ++b) { 7434 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7435 const PetscInt ind = indperm ? indperm[preind] : preind; 7436 7437 indices[ind] = off + foff + b; 7438 } 7439 } else { 7440 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7441 for (b = 0; b < fdof; ++b) { 7442 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7443 const PetscInt ind = indperm ? indperm[preind] : preind; 7444 7445 if ((cind < cfdof) && (b == fcdofs[cind])) { 7446 indices[ind] = -(off + foff + b + 1); 7447 ++cind; 7448 } else { 7449 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7450 } 7451 } 7452 } 7453 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7454 foffs[f] += fdof; 7455 } 7456 PetscFunctionReturn(PETSC_SUCCESS); 7457 } 7458 7459 /* 7460 This version believes the globalSection offsets for each field, rather than just the point offset 7461 7462 . foffs - The offset into 'indices' for each field, since it is segregated by field 7463 7464 Notes: 7465 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7466 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7467 */ 7468 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7469 { 7470 PetscInt numFields, foff, f; 7471 7472 PetscFunctionBegin; 7473 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7474 for (f = 0; f < numFields; ++f) { 7475 PetscInt fdof, cfdof; 7476 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7477 PetscInt cind = 0, b; 7478 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7479 7480 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7481 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7482 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7483 if (!cfdof) { 7484 for (b = 0; b < fdof; ++b) { 7485 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7486 const PetscInt ind = indperm ? indperm[preind] : preind; 7487 7488 indices[ind] = foff + b; 7489 } 7490 } else { 7491 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7492 for (b = 0; b < fdof; ++b) { 7493 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7494 const PetscInt ind = indperm ? indperm[preind] : preind; 7495 7496 if ((cind < cfdof) && (b == fcdofs[cind])) { 7497 indices[ind] = -(foff + b + 1); 7498 ++cind; 7499 } else { 7500 indices[ind] = foff + b - cind; 7501 } 7502 } 7503 } 7504 foffs[f] += fdof; 7505 } 7506 PetscFunctionReturn(PETSC_SUCCESS); 7507 } 7508 7509 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7510 { 7511 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7512 7513 PetscFunctionBegin; 7514 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7515 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7516 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7517 for (PetscInt p = 0; p < nPoints; p++) { 7518 PetscInt b = pnts[2 * p]; 7519 PetscInt bSecDof = 0, bOff; 7520 PetscInt cSecDof = 0; 7521 PetscSection indices_section; 7522 7523 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7524 if (!bSecDof) continue; 7525 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7526 indices_section = cSecDof > 0 ? cSec : section; 7527 if (numFields) { 7528 PetscInt fStart[32], fEnd[32]; 7529 7530 fStart[0] = 0; 7531 fEnd[0] = 0; 7532 for (PetscInt f = 0; f < numFields; f++) { 7533 PetscInt fDof = 0; 7534 7535 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7536 fStart[f + 1] = fStart[f] + fDof; 7537 fEnd[f + 1] = fStart[f + 1]; 7538 } 7539 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7540 // only apply permutations on one side 7541 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7542 for (PetscInt f = 0; f < numFields; f++) { 7543 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7544 } 7545 } else { 7546 PetscInt bEnd = 0; 7547 7548 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7549 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7550 7551 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7552 } 7553 } 7554 PetscFunctionReturn(PETSC_SUCCESS); 7555 } 7556 7557 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[]) 7558 { 7559 Mat cMat; 7560 PetscSection aSec, cSec; 7561 IS aIS; 7562 PetscInt aStart = -1, aEnd = -1; 7563 PetscInt sStart = -1, sEnd = -1; 7564 PetscInt cStart = -1, cEnd = -1; 7565 const PetscInt *anchors; 7566 PetscInt numFields, p; 7567 PetscInt newNumPoints = 0, newNumIndices = 0; 7568 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7569 PetscInt oldOffsets[32]; 7570 PetscInt newOffsets[32]; 7571 PetscInt oldOffsetsCopy[32]; 7572 PetscInt newOffsetsCopy[32]; 7573 PetscScalar *modMat = NULL; 7574 PetscBool anyConstrained = PETSC_FALSE; 7575 7576 PetscFunctionBegin; 7577 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7578 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7579 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7580 7581 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7582 /* if there are point-to-point constraints */ 7583 if (aSec) { 7584 PetscCall(PetscArrayzero(newOffsets, 32)); 7585 PetscCall(PetscArrayzero(oldOffsets, 32)); 7586 PetscCall(ISGetIndices(aIS, &anchors)); 7587 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7588 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7589 /* figure out how many points are going to be in the new element matrix 7590 * (we allow double counting, because it's all just going to be summed 7591 * into the global matrix anyway) */ 7592 for (p = 0; p < 2 * numPoints; p += 2) { 7593 PetscInt b = points[p]; 7594 PetscInt bDof = 0, bSecDof = 0; 7595 7596 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7597 if (!bSecDof) continue; 7598 7599 for (PetscInt f = 0; f < numFields; f++) { 7600 PetscInt fDof = 0; 7601 7602 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7603 oldOffsets[f + 1] += fDof; 7604 } 7605 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7606 if (bDof) { 7607 /* this point is constrained */ 7608 /* it is going to be replaced by its anchors */ 7609 PetscInt bOff, q; 7610 7611 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7612 for (q = 0; q < bDof; q++) { 7613 PetscInt a = anchors[bOff + q]; 7614 PetscInt aDof = 0; 7615 7616 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7617 if (aDof) { 7618 anyConstrained = PETSC_TRUE; 7619 newNumPoints += 1; 7620 } 7621 newNumIndices += aDof; 7622 for (PetscInt f = 0; f < numFields; ++f) { 7623 PetscInt fDof = 0; 7624 7625 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7626 newOffsets[f + 1] += fDof; 7627 } 7628 } 7629 } else { 7630 /* this point is not constrained */ 7631 newNumPoints++; 7632 newNumIndices += bSecDof; 7633 for (PetscInt f = 0; f < numFields; ++f) { 7634 PetscInt fDof; 7635 7636 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7637 newOffsets[f + 1] += fDof; 7638 } 7639 } 7640 } 7641 } 7642 if (!anyConstrained) { 7643 if (outNumPoints) *outNumPoints = 0; 7644 if (outNumIndices) *outNumIndices = 0; 7645 if (outPoints) *outPoints = NULL; 7646 if (outMat) *outMat = NULL; 7647 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7648 PetscFunctionReturn(PETSC_SUCCESS); 7649 } 7650 7651 if (outNumPoints) *outNumPoints = newNumPoints; 7652 if (outNumIndices) *outNumIndices = newNumIndices; 7653 7654 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7655 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7656 7657 if (!outPoints && !outMat) { 7658 if (offsets) { 7659 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7660 } 7661 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7662 PetscFunctionReturn(PETSC_SUCCESS); 7663 } 7664 7665 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7666 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7667 7668 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7669 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7670 7671 /* output arrays */ 7672 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7673 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7674 7675 // get the new Points 7676 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7677 PetscInt b = points[2 * p]; 7678 PetscInt bDof = 0, bSecDof = 0, bOff; 7679 7680 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7681 if (!bSecDof) continue; 7682 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7683 if (bDof) { 7684 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7685 for (PetscInt q = 0; q < bDof; q++) { 7686 PetscInt a = anchors[bOff + q], aDof = 0; 7687 7688 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7689 if (aDof) { 7690 newPoints[2 * newP] = a; 7691 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7692 newP++; 7693 } 7694 } 7695 } else { 7696 newPoints[2 * newP] = b; 7697 newPoints[2 * newP + 1] = points[2 * p + 1]; 7698 newP++; 7699 } 7700 } 7701 7702 if (outMat) { 7703 PetscScalar *tmpMat; 7704 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7705 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7706 7707 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7708 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7709 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7710 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7711 7712 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7713 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7714 7715 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7716 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7717 7718 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7719 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7720 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7721 // for each field, insert the anchor modification into modMat 7722 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7723 PetscInt fStart = oldOffsets[f]; 7724 PetscInt fNewStart = newOffsets[f]; 7725 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7726 PetscInt b = points[2 * p]; 7727 PetscInt bDof = 0, bSecDof = 0, bOff; 7728 7729 if (b >= sStart && b < sEnd) { 7730 if (numFields) { 7731 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7732 } else { 7733 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7734 } 7735 } 7736 if (!bSecDof) continue; 7737 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7738 if (bDof) { 7739 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7740 for (PetscInt q = 0; q < bDof; q++, newP++) { 7741 PetscInt a = anchors[bOff + q], aDof = 0; 7742 7743 if (a >= sStart && a < sEnd) { 7744 if (numFields) { 7745 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7746 } else { 7747 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7748 } 7749 } 7750 if (aDof) { 7751 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7752 for (PetscInt d = 0; d < bSecDof; d++) { 7753 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7754 } 7755 } 7756 oNew += aDof; 7757 } 7758 } else { 7759 // Insert the identity matrix in this block 7760 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7761 oNew += bSecDof; 7762 newP++; 7763 } 7764 o += bSecDof; 7765 } 7766 } 7767 7768 *outMat = modMat; 7769 7770 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7771 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7772 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7773 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7774 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7775 } 7776 PetscCall(ISRestoreIndices(aIS, &anchors)); 7777 7778 /* output */ 7779 if (outPoints) { 7780 *outPoints = newPoints; 7781 } else { 7782 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7783 } 7784 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7785 PetscFunctionReturn(PETSC_SUCCESS); 7786 } 7787 7788 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) 7789 { 7790 PetscScalar *modMat = NULL; 7791 PetscInt newNumIndices = -1; 7792 7793 PetscFunctionBegin; 7794 /* 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. 7795 modMat is that matrix C */ 7796 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7797 if (outNumIndices) *outNumIndices = newNumIndices; 7798 if (modMat) { 7799 const PetscScalar *newValues = values; 7800 7801 if (multiplyRight) { 7802 PetscScalar *newNewValues = NULL; 7803 PetscBLASInt M = newNumIndices; 7804 PetscBLASInt N = numRows; 7805 PetscBLASInt K = numIndices; 7806 PetscScalar a = 1.0, b = 0.0; 7807 7808 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); 7809 7810 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7811 // row-major to column-major conversion, right multiplication becomes left multiplication 7812 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7813 7814 numCols = newNumIndices; 7815 newValues = newNewValues; 7816 } 7817 7818 if (multiplyLeft) { 7819 PetscScalar *newNewValues = NULL; 7820 PetscBLASInt M = numCols; 7821 PetscBLASInt N = newNumIndices; 7822 PetscBLASInt K = numIndices; 7823 PetscScalar a = 1.0, b = 0.0; 7824 7825 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); 7826 7827 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7828 // row-major to column-major conversion, left multiplication becomes right multiplication 7829 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7830 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7831 newValues = newNewValues; 7832 } 7833 *outValues = (PetscScalar *)newValues; 7834 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7835 } 7836 PetscFunctionReturn(PETSC_SUCCESS); 7837 } 7838 7839 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) 7840 { 7841 PetscFunctionBegin; 7842 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7843 PetscFunctionReturn(PETSC_SUCCESS); 7844 } 7845 7846 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7847 { 7848 /* Closure ordering */ 7849 PetscSection clSection; 7850 IS clPoints; 7851 const PetscInt *clp; 7852 PetscInt *points; 7853 PetscInt Ncl, Ni = 0; 7854 7855 PetscFunctionBeginHot; 7856 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7857 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7858 PetscInt dof; 7859 7860 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7861 Ni += dof; 7862 } 7863 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7864 *closureSize = Ni; 7865 PetscFunctionReturn(PETSC_SUCCESS); 7866 } 7867 7868 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) 7869 { 7870 /* Closure ordering */ 7871 PetscSection clSection; 7872 IS clPoints; 7873 const PetscInt *clp; 7874 PetscInt *points; 7875 const PetscInt *clperm = NULL; 7876 /* Dof permutation and sign flips */ 7877 const PetscInt **perms[32] = {NULL}; 7878 const PetscScalar **flips[32] = {NULL}; 7879 PetscScalar *valCopy = NULL; 7880 /* Hanging node constraints */ 7881 PetscInt *pointsC = NULL; 7882 PetscScalar *valuesC = NULL; 7883 PetscInt NclC, NiC; 7884 7885 PetscInt *idx; 7886 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7887 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7888 PetscInt idxStart, idxEnd; 7889 PetscInt nRows, nCols; 7890 7891 PetscFunctionBeginHot; 7892 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7893 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7894 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7895 PetscAssertPointer(numRows, 6); 7896 PetscAssertPointer(numCols, 7); 7897 if (indices) PetscAssertPointer(indices, 8); 7898 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7899 if (values) PetscAssertPointer(values, 10); 7900 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7901 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7902 PetscCall(PetscArrayzero(offsets, 32)); 7903 /* 1) Get points in closure */ 7904 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7905 if (useClPerm) { 7906 PetscInt depth, clsize; 7907 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7908 for (clsize = 0, p = 0; p < Ncl; p++) { 7909 PetscInt dof; 7910 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7911 clsize += dof; 7912 } 7913 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7914 } 7915 /* 2) Get number of indices on these points and field offsets from section */ 7916 for (p = 0; p < Ncl * 2; p += 2) { 7917 PetscInt dof, fdof; 7918 7919 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7920 for (f = 0; f < Nf; ++f) { 7921 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7922 offsets[f + 1] += fdof; 7923 } 7924 Ni += dof; 7925 } 7926 if (*numRows == -1) *numRows = Ni; 7927 if (*numCols == -1) *numCols = Ni; 7928 nRows = *numRows; 7929 nCols = *numCols; 7930 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7931 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7932 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7933 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7934 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7935 for (f = 0; f < PetscMax(1, Nf); ++f) { 7936 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7937 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7938 /* may need to apply sign changes to the element matrix */ 7939 if (values && flips[f]) { 7940 PetscInt foffset = offsets[f]; 7941 7942 for (p = 0; p < Ncl; ++p) { 7943 PetscInt pnt = points[2 * p], fdof; 7944 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7945 7946 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7947 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7948 if (flip) { 7949 PetscInt i, j, k; 7950 7951 if (!valCopy) { 7952 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7953 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7954 *values = valCopy; 7955 } 7956 for (i = 0; i < fdof; ++i) { 7957 PetscScalar fval = flip[i]; 7958 7959 if (multiplyRight) { 7960 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7961 } 7962 if (multiplyLeft) { 7963 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7964 } 7965 } 7966 } 7967 foffset += fdof; 7968 } 7969 } 7970 } 7971 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7972 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7973 if (NclC) { 7974 if (multiplyRight) { *numCols = nCols = NiC; } 7975 if (multiplyLeft) { *numRows = nRows = NiC; } 7976 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7977 for (f = 0; f < PetscMax(1, Nf); ++f) { 7978 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7979 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7980 } 7981 for (f = 0; f < PetscMax(1, Nf); ++f) { 7982 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7983 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7984 } 7985 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7986 Ncl = NclC; 7987 Ni = NiC; 7988 points = pointsC; 7989 if (values) *values = valuesC; 7990 } 7991 /* 5) Calculate indices */ 7992 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7993 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 7994 if (Nf) { 7995 PetscInt idxOff; 7996 PetscBool useFieldOffsets; 7997 7998 if (outOffsets) { 7999 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8000 } 8001 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8002 if (useFieldOffsets) { 8003 for (p = 0; p < Ncl; ++p) { 8004 const PetscInt pnt = points[p * 2]; 8005 8006 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8007 } 8008 } else { 8009 for (p = 0; p < Ncl; ++p) { 8010 const PetscInt pnt = points[p * 2]; 8011 8012 if (pnt < idxStart || pnt >= idxEnd) continue; 8013 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8014 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8015 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8016 * global section. */ 8017 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8018 } 8019 } 8020 } else { 8021 PetscInt off = 0, idxOff; 8022 8023 for (p = 0; p < Ncl; ++p) { 8024 const PetscInt pnt = points[p * 2]; 8025 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8026 8027 if (pnt < idxStart || pnt >= idxEnd) continue; 8028 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8029 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8030 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8031 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8032 } 8033 } 8034 /* 6) Cleanup */ 8035 for (f = 0; f < PetscMax(1, Nf); ++f) { 8036 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8037 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8038 } 8039 if (NclC) { 8040 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8041 } else { 8042 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8043 } 8044 8045 if (indices) *indices = idx; 8046 PetscFunctionReturn(PETSC_SUCCESS); 8047 } 8048 8049 /*@C 8050 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8051 8052 Not collective 8053 8054 Input Parameters: 8055 + dm - The `DM` 8056 . section - The `PetscSection` describing the points (a local section) 8057 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8058 . point - The point defining the closure 8059 - useClPerm - Use the closure point permutation if available 8060 8061 Output Parameters: 8062 + numIndices - The number of dof indices in the closure of point with the input sections 8063 . indices - The dof indices 8064 . outOffsets - Array to write the field offsets into, or `NULL` 8065 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8066 8067 Level: advanced 8068 8069 Notes: 8070 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 8071 8072 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8073 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8074 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8075 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8076 indices (with the above semantics) are implied. 8077 8078 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8079 `PetscSection`, `DMGetGlobalSection()` 8080 @*/ 8081 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8082 { 8083 PetscInt numRows = -1, numCols = -1; 8084 8085 PetscFunctionBeginHot; 8086 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8087 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8088 *numIndices = numRows; 8089 PetscFunctionReturn(PETSC_SUCCESS); 8090 } 8091 8092 /*@C 8093 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8094 8095 Not collective 8096 8097 Input Parameters: 8098 + dm - The `DM` 8099 . section - The `PetscSection` describing the points (a local section) 8100 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8101 . point - The point defining the closure 8102 - useClPerm - Use the closure point permutation if available 8103 8104 Output Parameters: 8105 + numIndices - The number of dof indices in the closure of point with the input sections 8106 . indices - The dof indices 8107 . outOffsets - Array to write the field offsets into, or `NULL` 8108 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8109 8110 Level: advanced 8111 8112 Notes: 8113 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8114 8115 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8116 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8117 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8118 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8119 indices (with the above semantics) are implied. 8120 8121 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8122 @*/ 8123 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8124 { 8125 PetscFunctionBegin; 8126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8127 PetscAssertPointer(indices, 7); 8128 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8129 PetscFunctionReturn(PETSC_SUCCESS); 8130 } 8131 8132 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8133 { 8134 DM_Plex *mesh = (DM_Plex *)dm->data; 8135 PetscInt *indices; 8136 PetscInt numIndices; 8137 const PetscScalar *valuesOrig = values; 8138 PetscErrorCode ierr; 8139 8140 PetscFunctionBegin; 8141 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8142 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8143 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8144 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8145 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8146 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8147 8148 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8149 8150 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8151 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8152 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8153 if (ierr) { 8154 PetscMPIInt rank; 8155 8156 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8157 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8158 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8159 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8160 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8161 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8162 } 8163 if (mesh->printFEM > 1) { 8164 PetscInt i; 8165 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8166 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8167 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8168 } 8169 8170 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8171 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8172 PetscFunctionReturn(PETSC_SUCCESS); 8173 } 8174 8175 /*@C 8176 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8177 8178 Not collective 8179 8180 Input Parameters: 8181 + dm - The `DM` 8182 . section - The section describing the layout in `v`, or `NULL` to use the default section 8183 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8184 . A - The matrix 8185 . point - The point in the `DM` 8186 . values - The array of values 8187 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8188 8189 Level: intermediate 8190 8191 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8192 @*/ 8193 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8194 { 8195 PetscFunctionBegin; 8196 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8197 PetscFunctionReturn(PETSC_SUCCESS); 8198 } 8199 8200 /*@C 8201 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8202 8203 Not collective 8204 8205 Input Parameters: 8206 + dmRow - The `DM` for the row fields 8207 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8208 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8209 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8210 . dmCol - The `DM` for the column fields 8211 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8212 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8213 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8214 . A - The matrix 8215 . point - The point in the `DM` 8216 . values - The array of values 8217 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8218 8219 Level: intermediate 8220 8221 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8222 @*/ 8223 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) 8224 { 8225 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8226 PetscInt *indicesRow, *indicesCol; 8227 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8228 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8229 8230 PetscErrorCode ierr; 8231 8232 PetscFunctionBegin; 8233 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8234 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8235 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8236 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8237 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8238 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8239 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8240 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8241 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8242 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8243 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8244 8245 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8246 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8247 valuesV1 = valuesV0; 8248 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8249 valuesV2 = valuesV1; 8250 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8251 8252 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8253 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8254 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8255 if (ierr) { 8256 PetscMPIInt rank; 8257 8258 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8259 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8260 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8261 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8262 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8263 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8264 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8265 } 8266 8267 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8268 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8269 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8270 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8271 PetscFunctionReturn(PETSC_SUCCESS); 8272 } 8273 8274 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8275 { 8276 DM_Plex *mesh = (DM_Plex *)dmf->data; 8277 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8278 PetscInt *cpoints = NULL; 8279 PetscInt *findices, *cindices; 8280 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8281 PetscInt foffsets[32], coffsets[32]; 8282 DMPolytopeType ct; 8283 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8284 PetscErrorCode ierr; 8285 8286 PetscFunctionBegin; 8287 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8288 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8289 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8290 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8291 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8292 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8293 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8294 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8295 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8296 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8297 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8298 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8299 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8300 PetscCall(PetscArrayzero(foffsets, 32)); 8301 PetscCall(PetscArrayzero(coffsets, 32)); 8302 /* Column indices */ 8303 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8304 maxFPoints = numCPoints; 8305 /* Compress out points not in the section */ 8306 /* TODO: Squeeze out points with 0 dof as well */ 8307 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8308 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8309 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8310 cpoints[q * 2] = cpoints[p]; 8311 cpoints[q * 2 + 1] = cpoints[p + 1]; 8312 ++q; 8313 } 8314 } 8315 numCPoints = q; 8316 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8317 PetscInt fdof; 8318 8319 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8320 if (!dof) continue; 8321 for (f = 0; f < numFields; ++f) { 8322 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8323 coffsets[f + 1] += fdof; 8324 } 8325 numCIndices += dof; 8326 } 8327 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8328 /* Row indices */ 8329 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8330 { 8331 DMPlexTransform tr; 8332 DMPolytopeType *rct; 8333 PetscInt *rsize, *rcone, *rornt, Nt; 8334 8335 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8336 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8337 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8338 numSubcells = rsize[Nt - 1]; 8339 PetscCall(DMPlexTransformDestroy(&tr)); 8340 } 8341 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8342 for (r = 0, q = 0; r < numSubcells; ++r) { 8343 /* TODO Map from coarse to fine cells */ 8344 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8345 /* Compress out points not in the section */ 8346 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8347 for (p = 0; p < numFPoints * 2; p += 2) { 8348 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8349 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8350 if (!dof) continue; 8351 for (s = 0; s < q; ++s) 8352 if (fpoints[p] == ftotpoints[s * 2]) break; 8353 if (s < q) continue; 8354 ftotpoints[q * 2] = fpoints[p]; 8355 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8356 ++q; 8357 } 8358 } 8359 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8360 } 8361 numFPoints = q; 8362 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8363 PetscInt fdof; 8364 8365 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8366 if (!dof) continue; 8367 for (f = 0; f < numFields; ++f) { 8368 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8369 foffsets[f + 1] += fdof; 8370 } 8371 numFIndices += dof; 8372 } 8373 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8374 8375 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8376 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8377 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8378 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8379 if (numFields) { 8380 const PetscInt **permsF[32] = {NULL}; 8381 const PetscInt **permsC[32] = {NULL}; 8382 8383 for (f = 0; f < numFields; f++) { 8384 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8385 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8386 } 8387 for (p = 0; p < numFPoints; p++) { 8388 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8389 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8390 } 8391 for (p = 0; p < numCPoints; p++) { 8392 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8393 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8394 } 8395 for (f = 0; f < numFields; f++) { 8396 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8397 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8398 } 8399 } else { 8400 const PetscInt **permsF = NULL; 8401 const PetscInt **permsC = NULL; 8402 8403 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8404 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8405 for (p = 0, off = 0; p < numFPoints; p++) { 8406 const PetscInt *perm = permsF ? permsF[p] : NULL; 8407 8408 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8409 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8410 } 8411 for (p = 0, off = 0; p < numCPoints; p++) { 8412 const PetscInt *perm = permsC ? permsC[p] : NULL; 8413 8414 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8415 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8416 } 8417 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8418 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8419 } 8420 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8421 /* TODO: flips */ 8422 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8423 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8424 if (ierr) { 8425 PetscMPIInt rank; 8426 8427 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8428 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8429 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8430 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8431 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8432 } 8433 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8434 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8435 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8436 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8437 PetscFunctionReturn(PETSC_SUCCESS); 8438 } 8439 8440 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8441 { 8442 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8443 PetscInt *cpoints = NULL; 8444 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8445 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8446 DMPolytopeType ct; 8447 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8448 8449 PetscFunctionBegin; 8450 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8451 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8452 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8453 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8454 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8455 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8456 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8457 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8458 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8459 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8460 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8461 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8462 /* Column indices */ 8463 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8464 maxFPoints = numCPoints; 8465 /* Compress out points not in the section */ 8466 /* TODO: Squeeze out points with 0 dof as well */ 8467 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8468 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8469 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8470 cpoints[q * 2] = cpoints[p]; 8471 cpoints[q * 2 + 1] = cpoints[p + 1]; 8472 ++q; 8473 } 8474 } 8475 numCPoints = q; 8476 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8477 PetscInt fdof; 8478 8479 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8480 if (!dof) continue; 8481 for (f = 0; f < numFields; ++f) { 8482 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8483 coffsets[f + 1] += fdof; 8484 } 8485 numCIndices += dof; 8486 } 8487 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8488 /* Row indices */ 8489 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8490 { 8491 DMPlexTransform tr; 8492 DMPolytopeType *rct; 8493 PetscInt *rsize, *rcone, *rornt, Nt; 8494 8495 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8496 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8497 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8498 numSubcells = rsize[Nt - 1]; 8499 PetscCall(DMPlexTransformDestroy(&tr)); 8500 } 8501 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8502 for (r = 0, q = 0; r < numSubcells; ++r) { 8503 /* TODO Map from coarse to fine cells */ 8504 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8505 /* Compress out points not in the section */ 8506 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8507 for (p = 0; p < numFPoints * 2; p += 2) { 8508 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8509 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8510 if (!dof) continue; 8511 for (s = 0; s < q; ++s) 8512 if (fpoints[p] == ftotpoints[s * 2]) break; 8513 if (s < q) continue; 8514 ftotpoints[q * 2] = fpoints[p]; 8515 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8516 ++q; 8517 } 8518 } 8519 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8520 } 8521 numFPoints = q; 8522 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8523 PetscInt fdof; 8524 8525 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8526 if (!dof) continue; 8527 for (f = 0; f < numFields; ++f) { 8528 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8529 foffsets[f + 1] += fdof; 8530 } 8531 numFIndices += dof; 8532 } 8533 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8534 8535 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8536 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8537 if (numFields) { 8538 const PetscInt **permsF[32] = {NULL}; 8539 const PetscInt **permsC[32] = {NULL}; 8540 8541 for (f = 0; f < numFields; f++) { 8542 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8543 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8544 } 8545 for (p = 0; p < numFPoints; p++) { 8546 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8547 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8548 } 8549 for (p = 0; p < numCPoints; p++) { 8550 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8551 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8552 } 8553 for (f = 0; f < numFields; f++) { 8554 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8555 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8556 } 8557 } else { 8558 const PetscInt **permsF = NULL; 8559 const PetscInt **permsC = NULL; 8560 8561 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8562 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8563 for (p = 0, off = 0; p < numFPoints; p++) { 8564 const PetscInt *perm = permsF ? permsF[p] : NULL; 8565 8566 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8567 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8568 } 8569 for (p = 0, off = 0; p < numCPoints; p++) { 8570 const PetscInt *perm = permsC ? permsC[p] : NULL; 8571 8572 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8573 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8574 } 8575 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8576 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8577 } 8578 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8579 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8580 PetscFunctionReturn(PETSC_SUCCESS); 8581 } 8582 8583 /*@ 8584 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8585 8586 Input Parameter: 8587 . dm - The `DMPLEX` object 8588 8589 Output Parameter: 8590 . cellHeight - The height of a cell 8591 8592 Level: developer 8593 8594 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8595 @*/ 8596 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8597 { 8598 DM_Plex *mesh = (DM_Plex *)dm->data; 8599 8600 PetscFunctionBegin; 8601 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8602 PetscAssertPointer(cellHeight, 2); 8603 *cellHeight = mesh->vtkCellHeight; 8604 PetscFunctionReturn(PETSC_SUCCESS); 8605 } 8606 8607 /*@ 8608 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8609 8610 Input Parameters: 8611 + dm - The `DMPLEX` object 8612 - cellHeight - The height of a cell 8613 8614 Level: developer 8615 8616 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8617 @*/ 8618 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8619 { 8620 DM_Plex *mesh = (DM_Plex *)dm->data; 8621 8622 PetscFunctionBegin; 8623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8624 mesh->vtkCellHeight = cellHeight; 8625 PetscFunctionReturn(PETSC_SUCCESS); 8626 } 8627 8628 /*@ 8629 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8630 8631 Input Parameters: 8632 + dm - The `DMPLEX` object 8633 - ct - The `DMPolytopeType` of the cell 8634 8635 Output Parameters: 8636 + start - The first cell of this type, or `NULL` 8637 - end - The upper bound on this celltype, or `NULL` 8638 8639 Level: advanced 8640 8641 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8642 @*/ 8643 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8644 { 8645 DM_Plex *mesh = (DM_Plex *)dm->data; 8646 DMLabel label; 8647 PetscInt pStart, pEnd; 8648 8649 PetscFunctionBegin; 8650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8651 if (start) { 8652 PetscAssertPointer(start, 3); 8653 *start = 0; 8654 } 8655 if (end) { 8656 PetscAssertPointer(end, 4); 8657 *end = 0; 8658 } 8659 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8660 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8661 if (mesh->tr) { 8662 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8663 } else { 8664 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8665 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8666 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8667 } 8668 PetscFunctionReturn(PETSC_SUCCESS); 8669 } 8670 8671 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8672 { 8673 PetscSection section, globalSection; 8674 PetscInt *numbers, p; 8675 8676 PetscFunctionBegin; 8677 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8678 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8679 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8680 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8681 PetscCall(PetscSectionSetUp(section)); 8682 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8683 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8684 for (p = pStart; p < pEnd; ++p) { 8685 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8686 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8687 else numbers[p - pStart] += shift; 8688 } 8689 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8690 if (globalSize) { 8691 PetscLayout layout; 8692 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8693 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8694 PetscCall(PetscLayoutDestroy(&layout)); 8695 } 8696 PetscCall(PetscSectionDestroy(§ion)); 8697 PetscCall(PetscSectionDestroy(&globalSection)); 8698 PetscFunctionReturn(PETSC_SUCCESS); 8699 } 8700 8701 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8702 { 8703 PetscInt cellHeight, cStart, cEnd; 8704 8705 PetscFunctionBegin; 8706 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8707 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8708 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8709 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8710 PetscFunctionReturn(PETSC_SUCCESS); 8711 } 8712 8713 /*@ 8714 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8715 8716 Input Parameter: 8717 . dm - The `DMPLEX` object 8718 8719 Output Parameter: 8720 . globalCellNumbers - Global cell numbers for all cells on this process 8721 8722 Level: developer 8723 8724 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8725 @*/ 8726 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8727 { 8728 DM_Plex *mesh = (DM_Plex *)dm->data; 8729 8730 PetscFunctionBegin; 8731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8732 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8733 *globalCellNumbers = mesh->globalCellNumbers; 8734 PetscFunctionReturn(PETSC_SUCCESS); 8735 } 8736 8737 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8738 { 8739 PetscInt vStart, vEnd; 8740 8741 PetscFunctionBegin; 8742 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8743 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8744 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8745 PetscFunctionReturn(PETSC_SUCCESS); 8746 } 8747 8748 /*@ 8749 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8750 8751 Input Parameter: 8752 . dm - The `DMPLEX` object 8753 8754 Output Parameter: 8755 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8756 8757 Level: developer 8758 8759 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8760 @*/ 8761 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8762 { 8763 DM_Plex *mesh = (DM_Plex *)dm->data; 8764 8765 PetscFunctionBegin; 8766 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8767 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8768 *globalVertexNumbers = mesh->globalVertexNumbers; 8769 PetscFunctionReturn(PETSC_SUCCESS); 8770 } 8771 8772 /*@ 8773 DMPlexCreatePointNumbering - Create a global numbering for all points. 8774 8775 Collective 8776 8777 Input Parameter: 8778 . dm - The `DMPLEX` object 8779 8780 Output Parameter: 8781 . globalPointNumbers - Global numbers for all points on this process 8782 8783 Level: developer 8784 8785 Notes: 8786 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8787 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8788 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8789 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8790 8791 The partitioned mesh is 8792 ``` 8793 (2)--0--(3)--1--(4) (1)--0--(2) 8794 ``` 8795 and its global numbering is 8796 ``` 8797 (3)--0--(4)--1--(5)--2--(6) 8798 ``` 8799 Then the global numbering is provided as 8800 ``` 8801 [0] Number of indices in set 5 8802 [0] 0 0 8803 [0] 1 1 8804 [0] 2 3 8805 [0] 3 4 8806 [0] 4 -6 8807 [1] Number of indices in set 3 8808 [1] 0 2 8809 [1] 1 5 8810 [1] 2 6 8811 ``` 8812 8813 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8814 @*/ 8815 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8816 { 8817 IS nums[4]; 8818 PetscInt depths[4], gdepths[4], starts[4]; 8819 PetscInt depth, d, shift = 0; 8820 PetscBool empty = PETSC_FALSE; 8821 8822 PetscFunctionBegin; 8823 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8824 PetscCall(DMPlexGetDepth(dm, &depth)); 8825 // For unstratified meshes use dim instead of depth 8826 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8827 // If any stratum is empty, we must mark all empty 8828 for (d = 0; d <= depth; ++d) { 8829 PetscInt end; 8830 8831 depths[d] = depth - d; 8832 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8833 if (!(starts[d] - end)) empty = PETSC_TRUE; 8834 } 8835 if (empty) 8836 for (d = 0; d <= depth; ++d) { 8837 depths[d] = -1; 8838 starts[d] = -1; 8839 } 8840 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8841 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8842 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]); 8843 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8844 for (d = 0; d <= depth; ++d) { 8845 PetscInt pStart, pEnd, gsize; 8846 8847 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8848 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8849 shift += gsize; 8850 } 8851 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8852 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8853 PetscFunctionReturn(PETSC_SUCCESS); 8854 } 8855 8856 /*@ 8857 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8858 8859 Collective 8860 8861 Input Parameter: 8862 . dm - The `DMPLEX` object 8863 8864 Output Parameter: 8865 . globalEdgeNumbers - Global numbers for all edges on this process 8866 8867 Level: developer 8868 8869 Notes: 8870 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). 8871 8872 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8873 @*/ 8874 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8875 { 8876 PetscSF sf; 8877 PetscInt eStart, eEnd; 8878 8879 PetscFunctionBegin; 8880 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8881 PetscCall(DMGetPointSF(dm, &sf)); 8882 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8883 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8884 PetscFunctionReturn(PETSC_SUCCESS); 8885 } 8886 8887 /*@ 8888 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8889 8890 Input Parameter: 8891 . dm - The `DMPLEX` object 8892 8893 Output Parameter: 8894 . ranks - The rank field 8895 8896 Options Database Key: 8897 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8898 8899 Level: intermediate 8900 8901 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8902 @*/ 8903 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8904 { 8905 DM rdm; 8906 PetscFE fe; 8907 PetscScalar *r; 8908 PetscMPIInt rank; 8909 DMPolytopeType ct; 8910 PetscInt dim, cStart, cEnd, c; 8911 PetscBool simplex; 8912 8913 PetscFunctionBeginUser; 8914 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8915 PetscAssertPointer(ranks, 2); 8916 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8917 PetscCall(DMClone(dm, &rdm)); 8918 PetscCall(DMGetDimension(rdm, &dim)); 8919 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8920 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8921 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8922 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8923 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8924 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8925 PetscCall(PetscFEDestroy(&fe)); 8926 PetscCall(DMCreateDS(rdm)); 8927 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8928 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8929 PetscCall(VecGetArray(*ranks, &r)); 8930 for (c = cStart; c < cEnd; ++c) { 8931 PetscScalar *lr; 8932 8933 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8934 if (lr) *lr = rank; 8935 } 8936 PetscCall(VecRestoreArray(*ranks, &r)); 8937 PetscCall(DMDestroy(&rdm)); 8938 PetscFunctionReturn(PETSC_SUCCESS); 8939 } 8940 8941 /*@ 8942 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8943 8944 Input Parameters: 8945 + dm - The `DMPLEX` 8946 - label - The `DMLabel` 8947 8948 Output Parameter: 8949 . val - The label value field 8950 8951 Options Database Key: 8952 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8953 8954 Level: intermediate 8955 8956 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8957 @*/ 8958 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8959 { 8960 DM rdm, plex; 8961 Vec lval; 8962 PetscSection section; 8963 PetscFE fe; 8964 PetscScalar *v; 8965 PetscInt dim, pStart, pEnd, p, cStart; 8966 DMPolytopeType ct; 8967 char name[PETSC_MAX_PATH_LEN]; 8968 const char *lname, *prefix; 8969 8970 PetscFunctionBeginUser; 8971 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8972 PetscAssertPointer(label, 2); 8973 PetscAssertPointer(val, 3); 8974 PetscCall(DMClone(dm, &rdm)); 8975 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8976 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8977 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8978 PetscCall(DMDestroy(&plex)); 8979 PetscCall(DMGetDimension(rdm, &dim)); 8980 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8981 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8982 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8983 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8984 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8985 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8986 PetscCall(PetscFEDestroy(&fe)); 8987 PetscCall(DMCreateDS(rdm)); 8988 PetscCall(DMCreateGlobalVector(rdm, val)); 8989 PetscCall(DMCreateLocalVector(rdm, &lval)); 8990 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8991 PetscCall(DMGetLocalSection(rdm, §ion)); 8992 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8993 PetscCall(VecGetArray(lval, &v)); 8994 for (p = pStart; p < pEnd; ++p) { 8995 PetscInt cval, dof, off; 8996 8997 PetscCall(PetscSectionGetDof(section, p, &dof)); 8998 if (!dof) continue; 8999 PetscCall(DMLabelGetValue(label, p, &cval)); 9000 PetscCall(PetscSectionGetOffset(section, p, &off)); 9001 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9002 } 9003 PetscCall(VecRestoreArray(lval, &v)); 9004 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9005 PetscCall(VecDestroy(&lval)); 9006 PetscCall(DMDestroy(&rdm)); 9007 PetscFunctionReturn(PETSC_SUCCESS); 9008 } 9009 9010 /*@ 9011 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9012 9013 Input Parameter: 9014 . dm - The `DMPLEX` object 9015 9016 Level: developer 9017 9018 Notes: 9019 This is a useful diagnostic when creating meshes programmatically. 9020 9021 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9022 9023 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9024 @*/ 9025 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9026 { 9027 PetscSection coneSection, supportSection; 9028 const PetscInt *cone, *support; 9029 PetscInt coneSize, c, supportSize, s; 9030 PetscInt pStart, pEnd, p, pp, csize, ssize; 9031 PetscBool storagecheck = PETSC_TRUE; 9032 9033 PetscFunctionBegin; 9034 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9035 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9036 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9037 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9038 /* Check that point p is found in the support of its cone points, and vice versa */ 9039 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9040 for (p = pStart; p < pEnd; ++p) { 9041 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9042 PetscCall(DMPlexGetCone(dm, p, &cone)); 9043 for (c = 0; c < coneSize; ++c) { 9044 PetscBool dup = PETSC_FALSE; 9045 PetscInt d; 9046 for (d = c - 1; d >= 0; --d) { 9047 if (cone[c] == cone[d]) { 9048 dup = PETSC_TRUE; 9049 break; 9050 } 9051 } 9052 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9053 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9054 for (s = 0; s < supportSize; ++s) { 9055 if (support[s] == p) break; 9056 } 9057 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9058 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9059 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9060 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9061 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9062 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9063 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9064 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]); 9065 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9066 } 9067 } 9068 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9069 if (p != pp) { 9070 storagecheck = PETSC_FALSE; 9071 continue; 9072 } 9073 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9074 PetscCall(DMPlexGetSupport(dm, p, &support)); 9075 for (s = 0; s < supportSize; ++s) { 9076 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9077 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9078 for (c = 0; c < coneSize; ++c) { 9079 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9080 if (cone[c] != pp) { 9081 c = 0; 9082 break; 9083 } 9084 if (cone[c] == p) break; 9085 } 9086 if (c >= coneSize) { 9087 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9088 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9089 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9090 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9091 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9092 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9093 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9094 } 9095 } 9096 } 9097 if (storagecheck) { 9098 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9099 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9100 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9101 } 9102 PetscFunctionReturn(PETSC_SUCCESS); 9103 } 9104 9105 /* 9106 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. 9107 */ 9108 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9109 { 9110 DMPolytopeType cct; 9111 PetscInt ptpoints[4]; 9112 const PetscInt *cone, *ccone, *ptcone; 9113 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9114 9115 PetscFunctionBegin; 9116 *unsplit = 0; 9117 switch (ct) { 9118 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9119 ptpoints[npt++] = c; 9120 break; 9121 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9122 PetscCall(DMPlexGetCone(dm, c, &cone)); 9123 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9124 for (cp = 0; cp < coneSize; ++cp) { 9125 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9126 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9127 } 9128 break; 9129 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9130 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9131 PetscCall(DMPlexGetCone(dm, c, &cone)); 9132 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9133 for (cp = 0; cp < coneSize; ++cp) { 9134 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9135 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9136 for (ccp = 0; ccp < cconeSize; ++ccp) { 9137 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9138 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9139 PetscInt p; 9140 for (p = 0; p < npt; ++p) 9141 if (ptpoints[p] == ccone[ccp]) break; 9142 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9143 } 9144 } 9145 } 9146 break; 9147 default: 9148 break; 9149 } 9150 for (pt = 0; pt < npt; ++pt) { 9151 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9152 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9153 } 9154 PetscFunctionReturn(PETSC_SUCCESS); 9155 } 9156 9157 /*@ 9158 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9159 9160 Input Parameters: 9161 + dm - The `DMPLEX` object 9162 - cellHeight - Normally 0 9163 9164 Level: developer 9165 9166 Notes: 9167 This is a useful diagnostic when creating meshes programmatically. 9168 Currently applicable only to homogeneous simplex or tensor meshes. 9169 9170 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9171 9172 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9173 @*/ 9174 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9175 { 9176 DMPlexInterpolatedFlag interp; 9177 DMPolytopeType ct; 9178 PetscInt vStart, vEnd, cStart, cEnd, c; 9179 9180 PetscFunctionBegin; 9181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9182 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9183 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9184 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9185 for (c = cStart; c < cEnd; ++c) { 9186 PetscInt *closure = NULL; 9187 PetscInt coneSize, closureSize, cl, Nv = 0; 9188 9189 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9190 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9191 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9192 if (interp == DMPLEX_INTERPOLATED_FULL) { 9193 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9194 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)); 9195 } 9196 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9197 for (cl = 0; cl < closureSize * 2; cl += 2) { 9198 const PetscInt p = closure[cl]; 9199 if ((p >= vStart) && (p < vEnd)) ++Nv; 9200 } 9201 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9202 /* Special Case: Tensor faces with identified vertices */ 9203 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9204 PetscInt unsplit; 9205 9206 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9207 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9208 } 9209 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)); 9210 } 9211 PetscFunctionReturn(PETSC_SUCCESS); 9212 } 9213 9214 /*@ 9215 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9216 9217 Collective 9218 9219 Input Parameters: 9220 + dm - The `DMPLEX` object 9221 - cellHeight - Normally 0 9222 9223 Level: developer 9224 9225 Notes: 9226 This is a useful diagnostic when creating meshes programmatically. 9227 This routine is only relevant for meshes that are fully interpolated across all ranks. 9228 It will error out if a partially interpolated mesh is given on some rank. 9229 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9230 9231 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9232 9233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9234 @*/ 9235 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9236 { 9237 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9238 DMPlexInterpolatedFlag interpEnum; 9239 9240 PetscFunctionBegin; 9241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9242 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9243 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9244 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9245 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9246 PetscFunctionReturn(PETSC_SUCCESS); 9247 } 9248 9249 PetscCall(DMGetDimension(dm, &dim)); 9250 PetscCall(DMPlexGetDepth(dm, &depth)); 9251 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9252 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9253 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9254 for (c = cStart; c < cEnd; ++c) { 9255 const PetscInt *cone, *ornt, *faceSizes, *faces; 9256 const DMPolytopeType *faceTypes; 9257 DMPolytopeType ct; 9258 PetscInt numFaces, coneSize, f; 9259 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9260 9261 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9262 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9263 if (unsplit) continue; 9264 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9265 PetscCall(DMPlexGetCone(dm, c, &cone)); 9266 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9267 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9268 for (cl = 0; cl < closureSize * 2; cl += 2) { 9269 const PetscInt p = closure[cl]; 9270 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9271 } 9272 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9273 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); 9274 for (f = 0; f < numFaces; ++f) { 9275 DMPolytopeType fct; 9276 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9277 9278 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9279 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9280 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9281 const PetscInt p = fclosure[cl]; 9282 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9283 } 9284 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]); 9285 for (v = 0; v < fnumCorners; ++v) { 9286 if (fclosure[v] != faces[fOff + v]) { 9287 PetscInt v1; 9288 9289 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9290 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9291 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9292 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9293 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9294 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]); 9295 } 9296 } 9297 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9298 fOff += faceSizes[f]; 9299 } 9300 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9301 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9302 } 9303 } 9304 PetscFunctionReturn(PETSC_SUCCESS); 9305 } 9306 9307 /*@ 9308 DMPlexCheckGeometry - Check the geometry of mesh cells 9309 9310 Input Parameter: 9311 . dm - The `DMPLEX` object 9312 9313 Level: developer 9314 9315 Notes: 9316 This is a useful diagnostic when creating meshes programmatically. 9317 9318 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9319 9320 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9321 @*/ 9322 PetscErrorCode DMPlexCheckGeometry(DM dm) 9323 { 9324 Vec coordinates; 9325 PetscReal detJ, J[9], refVol = 1.0; 9326 PetscReal vol; 9327 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9328 9329 PetscFunctionBegin; 9330 PetscCall(DMGetDimension(dm, &dim)); 9331 PetscCall(DMGetCoordinateDim(dm, &dE)); 9332 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9333 PetscCall(DMPlexGetDepth(dm, &depth)); 9334 for (d = 0; d < dim; ++d) refVol *= 2.0; 9335 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9336 /* Make sure local coordinates are created, because that step is collective */ 9337 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9338 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9339 for (c = cStart; c < cEnd; ++c) { 9340 DMPolytopeType ct; 9341 PetscInt unsplit; 9342 PetscBool ignoreZeroVol = PETSC_FALSE; 9343 9344 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9345 switch (ct) { 9346 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9347 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9348 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9349 ignoreZeroVol = PETSC_TRUE; 9350 break; 9351 default: 9352 break; 9353 } 9354 switch (ct) { 9355 case DM_POLYTOPE_TRI_PRISM: 9356 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9357 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9358 case DM_POLYTOPE_PYRAMID: 9359 continue; 9360 default: 9361 break; 9362 } 9363 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9364 if (unsplit) continue; 9365 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9366 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); 9367 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9368 /* This should work with periodicity since DG coordinates should be used */ 9369 if (depth > 1) { 9370 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9371 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); 9372 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9373 } 9374 } 9375 PetscFunctionReturn(PETSC_SUCCESS); 9376 } 9377 9378 /*@ 9379 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9380 9381 Collective 9382 9383 Input Parameters: 9384 + dm - The `DMPLEX` object 9385 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9386 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9387 9388 Level: developer 9389 9390 Notes: 9391 This is mainly intended for debugging/testing purposes. 9392 9393 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9394 9395 Extra roots can come from periodic cuts, where additional points appear on the boundary 9396 9397 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9398 @*/ 9399 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9400 { 9401 PetscInt l, nleaves, nroots, overlap; 9402 const PetscInt *locals; 9403 const PetscSFNode *remotes; 9404 PetscBool distributed; 9405 MPI_Comm comm; 9406 PetscMPIInt rank; 9407 9408 PetscFunctionBegin; 9409 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9410 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9411 else pointSF = dm->sf; 9412 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9413 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9414 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9415 { 9416 PetscMPIInt mpiFlag; 9417 9418 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9419 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9420 } 9421 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9422 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9423 if (!distributed) { 9424 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); 9425 PetscFunctionReturn(PETSC_SUCCESS); 9426 } 9427 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); 9428 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9429 9430 /* Check SF graph is compatible with DMPlex chart */ 9431 { 9432 PetscInt pStart, pEnd, maxLeaf; 9433 9434 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9435 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9436 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9437 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9438 } 9439 9440 /* Check Point SF has no local points referenced */ 9441 for (l = 0; l < nleaves; l++) { 9442 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); 9443 } 9444 9445 /* Check there are no cells in interface */ 9446 if (!overlap) { 9447 PetscInt cellHeight, cStart, cEnd; 9448 9449 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9450 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9451 for (l = 0; l < nleaves; ++l) { 9452 const PetscInt point = locals ? locals[l] : l; 9453 9454 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9455 } 9456 } 9457 9458 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9459 { 9460 const PetscInt *rootdegree; 9461 9462 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9463 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9464 for (l = 0; l < nleaves; ++l) { 9465 const PetscInt point = locals ? locals[l] : l; 9466 const PetscInt *cone; 9467 PetscInt coneSize, c, idx; 9468 9469 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9470 PetscCall(DMPlexGetCone(dm, point, &cone)); 9471 for (c = 0; c < coneSize; ++c) { 9472 if (!rootdegree[cone[c]]) { 9473 if (locals) { 9474 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9475 } else { 9476 idx = (cone[c] < nleaves) ? cone[c] : -1; 9477 } 9478 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9479 } 9480 } 9481 } 9482 } 9483 PetscFunctionReturn(PETSC_SUCCESS); 9484 } 9485 9486 /*@ 9487 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9488 9489 Collective 9490 9491 Input Parameter: 9492 . dm - The `DMPLEX` object 9493 9494 Level: developer 9495 9496 Notes: 9497 This is mainly intended for debugging/testing purposes. 9498 9499 Other cell types which are disconnected would be caught by the symmetry and face checks. 9500 9501 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9502 9503 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9504 @*/ 9505 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9506 { 9507 PetscInt pStart, pEnd, vStart, vEnd; 9508 9509 PetscFunctionBegin; 9510 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9511 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9512 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9513 for (PetscInt v = vStart; v < vEnd; ++v) { 9514 PetscInt suppSize; 9515 9516 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9517 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9518 } 9519 PetscFunctionReturn(PETSC_SUCCESS); 9520 } 9521 9522 /*@ 9523 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9524 9525 Input Parameter: 9526 . dm - The `DMPLEX` object 9527 9528 Level: developer 9529 9530 Notes: 9531 This is a useful diagnostic when creating meshes programmatically. 9532 9533 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9534 9535 Currently does not include `DMPlexCheckCellShape()`. 9536 9537 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9538 @*/ 9539 PetscErrorCode DMPlexCheck(DM dm) 9540 { 9541 PetscInt cellHeight; 9542 9543 PetscFunctionBegin; 9544 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9545 PetscCall(DMPlexCheckSymmetry(dm)); 9546 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9547 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9548 PetscCall(DMPlexCheckGeometry(dm)); 9549 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9550 PetscCall(DMPlexCheckInterfaceCones(dm)); 9551 PetscCall(DMPlexCheckOrphanVertices(dm)); 9552 PetscFunctionReturn(PETSC_SUCCESS); 9553 } 9554 9555 typedef struct cell_stats { 9556 PetscReal min, max, sum, squaresum; 9557 PetscInt count; 9558 } cell_stats_t; 9559 9560 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9561 { 9562 PetscInt i, N = *len; 9563 9564 for (i = 0; i < N; i++) { 9565 cell_stats_t *A = (cell_stats_t *)a; 9566 cell_stats_t *B = (cell_stats_t *)b; 9567 9568 B->min = PetscMin(A->min, B->min); 9569 B->max = PetscMax(A->max, B->max); 9570 B->sum += A->sum; 9571 B->squaresum += A->squaresum; 9572 B->count += A->count; 9573 } 9574 } 9575 9576 /*@ 9577 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9578 9579 Collective 9580 9581 Input Parameters: 9582 + dm - The `DMPLEX` object 9583 . output - If true, statistics will be displayed on `stdout` 9584 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9585 9586 Level: developer 9587 9588 Notes: 9589 This is mainly intended for debugging/testing purposes. 9590 9591 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9592 9593 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9594 @*/ 9595 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9596 { 9597 DM dmCoarse; 9598 cell_stats_t stats, globalStats; 9599 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9600 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9601 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9602 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9603 PetscMPIInt rank, size; 9604 9605 PetscFunctionBegin; 9606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9607 stats.min = PETSC_MAX_REAL; 9608 stats.max = PETSC_MIN_REAL; 9609 stats.sum = stats.squaresum = 0.; 9610 stats.count = 0; 9611 9612 PetscCallMPI(MPI_Comm_size(comm, &size)); 9613 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9614 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9615 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9616 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9617 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9618 for (c = cStart; c < cEnd; c++) { 9619 PetscInt i; 9620 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9621 9622 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9623 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9624 for (i = 0; i < PetscSqr(cdim); ++i) { 9625 frobJ += J[i] * J[i]; 9626 frobInvJ += invJ[i] * invJ[i]; 9627 } 9628 cond2 = frobJ * frobInvJ; 9629 cond = PetscSqrtReal(cond2); 9630 9631 stats.min = PetscMin(stats.min, cond); 9632 stats.max = PetscMax(stats.max, cond); 9633 stats.sum += cond; 9634 stats.squaresum += cond2; 9635 stats.count++; 9636 if (output && cond > limit) { 9637 PetscSection coordSection; 9638 Vec coordsLocal; 9639 PetscScalar *coords = NULL; 9640 PetscInt Nv, d, clSize, cl, *closure = NULL; 9641 9642 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9643 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9644 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9645 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9646 for (i = 0; i < Nv / cdim; ++i) { 9647 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9648 for (d = 0; d < cdim; ++d) { 9649 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9650 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9651 } 9652 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9653 } 9654 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9655 for (cl = 0; cl < clSize * 2; cl += 2) { 9656 const PetscInt edge = closure[cl]; 9657 9658 if ((edge >= eStart) && (edge < eEnd)) { 9659 PetscReal len; 9660 9661 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9662 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9663 } 9664 } 9665 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9666 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9667 } 9668 } 9669 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9670 9671 if (size > 1) { 9672 PetscMPIInt blockLengths[2] = {4, 1}; 9673 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9674 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9675 MPI_Op statReduce; 9676 9677 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9678 PetscCallMPI(MPI_Type_commit(&statType)); 9679 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9680 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9681 PetscCallMPI(MPI_Op_free(&statReduce)); 9682 PetscCallMPI(MPI_Type_free(&statType)); 9683 } else { 9684 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9685 } 9686 if (rank == 0) { 9687 count = globalStats.count; 9688 min = globalStats.min; 9689 max = globalStats.max; 9690 mean = globalStats.sum / globalStats.count; 9691 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9692 } 9693 9694 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)); 9695 PetscCall(PetscFree2(J, invJ)); 9696 9697 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9698 if (dmCoarse) { 9699 PetscBool isplex; 9700 9701 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9702 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9703 } 9704 PetscFunctionReturn(PETSC_SUCCESS); 9705 } 9706 9707 /*@ 9708 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9709 orthogonal quality below given tolerance. 9710 9711 Collective 9712 9713 Input Parameters: 9714 + dm - The `DMPLEX` object 9715 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9716 - atol - [0, 1] Absolute tolerance for tagging cells. 9717 9718 Output Parameters: 9719 + OrthQual - `Vec` containing orthogonal quality per cell 9720 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9721 9722 Options Database Keys: 9723 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9724 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9725 9726 Level: intermediate 9727 9728 Notes: 9729 Orthogonal quality is given by the following formula\: 9730 9731 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9732 9733 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 9734 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9735 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9736 calculating the cosine of the angle between these vectors. 9737 9738 Orthogonal quality ranges from 1 (best) to 0 (worst). 9739 9740 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9741 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9742 9743 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9744 9745 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9746 @*/ 9747 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9748 { 9749 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9750 PetscInt *idx; 9751 PetscScalar *oqVals; 9752 const PetscScalar *cellGeomArr, *faceGeomArr; 9753 PetscReal *ci, *fi, *Ai; 9754 MPI_Comm comm; 9755 Vec cellgeom, facegeom; 9756 DM dmFace, dmCell; 9757 IS glob; 9758 ISLocalToGlobalMapping ltog; 9759 PetscViewer vwr; 9760 9761 PetscFunctionBegin; 9762 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9763 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9764 PetscAssertPointer(OrthQual, 4); 9765 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9766 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9767 PetscCall(DMGetDimension(dm, &nc)); 9768 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9769 { 9770 DMPlexInterpolatedFlag interpFlag; 9771 9772 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9773 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9774 PetscMPIInt rank; 9775 9776 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9777 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9778 } 9779 } 9780 if (OrthQualLabel) { 9781 PetscAssertPointer(OrthQualLabel, 5); 9782 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9783 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9784 } else { 9785 *OrthQualLabel = NULL; 9786 } 9787 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9788 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9789 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9790 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9791 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9792 PetscCall(VecCreate(comm, OrthQual)); 9793 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9794 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9795 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9796 PetscCall(VecSetUp(*OrthQual)); 9797 PetscCall(ISDestroy(&glob)); 9798 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9799 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9800 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9801 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9802 PetscCall(VecGetDM(cellgeom, &dmCell)); 9803 PetscCall(VecGetDM(facegeom, &dmFace)); 9804 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9805 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9806 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9807 PetscInt cellarr[2], *adj = NULL; 9808 PetscScalar *cArr, *fArr; 9809 PetscReal minvalc = 1.0, minvalf = 1.0; 9810 PetscFVCellGeom *cg; 9811 9812 idx[cellIter] = cell - cStart; 9813 cellarr[0] = cell; 9814 /* Make indexing into cellGeom easier */ 9815 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9816 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9817 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9818 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9819 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9820 PetscInt i; 9821 const PetscInt neigh = adj[cellneigh]; 9822 PetscReal normci = 0, normfi = 0, normai = 0; 9823 PetscFVCellGeom *cgneigh; 9824 PetscFVFaceGeom *fg; 9825 9826 /* Don't count ourselves in the neighbor list */ 9827 if (neigh == cell) continue; 9828 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9829 cellarr[1] = neigh; 9830 { 9831 PetscInt numcovpts; 9832 const PetscInt *covpts; 9833 9834 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9835 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9836 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9837 } 9838 9839 /* Compute c_i, f_i and their norms */ 9840 for (i = 0; i < nc; i++) { 9841 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9842 fi[i] = fg->centroid[i] - cg->centroid[i]; 9843 Ai[i] = fg->normal[i]; 9844 normci += PetscPowReal(ci[i], 2); 9845 normfi += PetscPowReal(fi[i], 2); 9846 normai += PetscPowReal(Ai[i], 2); 9847 } 9848 normci = PetscSqrtReal(normci); 9849 normfi = PetscSqrtReal(normfi); 9850 normai = PetscSqrtReal(normai); 9851 9852 /* Normalize and compute for each face-cell-normal pair */ 9853 for (i = 0; i < nc; i++) { 9854 ci[i] = ci[i] / normci; 9855 fi[i] = fi[i] / normfi; 9856 Ai[i] = Ai[i] / normai; 9857 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9858 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9859 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9860 } 9861 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9862 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9863 } 9864 PetscCall(PetscFree(adj)); 9865 PetscCall(PetscFree2(cArr, fArr)); 9866 /* Defer to cell if they're equal */ 9867 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9868 if (OrthQualLabel) { 9869 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9870 } 9871 } 9872 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9873 PetscCall(VecAssemblyBegin(*OrthQual)); 9874 PetscCall(VecAssemblyEnd(*OrthQual)); 9875 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9876 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9877 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9878 if (OrthQualLabel) { 9879 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9880 } 9881 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9882 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9883 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9884 PetscFunctionReturn(PETSC_SUCCESS); 9885 } 9886 9887 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9888 * interpolator construction */ 9889 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9890 { 9891 PetscSection section, newSection, gsection; 9892 PetscSF sf; 9893 PetscBool hasConstraints, ghasConstraints; 9894 9895 PetscFunctionBegin; 9896 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9897 PetscAssertPointer(odm, 2); 9898 PetscCall(DMGetLocalSection(dm, §ion)); 9899 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9900 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9901 if (!ghasConstraints) { 9902 PetscCall(PetscObjectReference((PetscObject)dm)); 9903 *odm = dm; 9904 PetscFunctionReturn(PETSC_SUCCESS); 9905 } 9906 PetscCall(DMClone(dm, odm)); 9907 PetscCall(DMCopyFields(dm, *odm)); 9908 PetscCall(DMGetLocalSection(*odm, &newSection)); 9909 PetscCall(DMGetPointSF(*odm, &sf)); 9910 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9911 PetscCall(DMSetGlobalSection(*odm, gsection)); 9912 PetscCall(PetscSectionDestroy(&gsection)); 9913 PetscFunctionReturn(PETSC_SUCCESS); 9914 } 9915 9916 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9917 { 9918 DM dmco, dmfo; 9919 Mat interpo; 9920 Vec rscale; 9921 Vec cglobalo, clocal; 9922 Vec fglobal, fglobalo, flocal; 9923 PetscBool regular; 9924 9925 PetscFunctionBegin; 9926 PetscCall(DMGetFullDM(dmc, &dmco)); 9927 PetscCall(DMGetFullDM(dmf, &dmfo)); 9928 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9929 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9930 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9931 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9932 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9933 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9934 PetscCall(VecSet(cglobalo, 0.)); 9935 PetscCall(VecSet(clocal, 0.)); 9936 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9937 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9938 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9939 PetscCall(VecSet(fglobal, 0.)); 9940 PetscCall(VecSet(fglobalo, 0.)); 9941 PetscCall(VecSet(flocal, 0.)); 9942 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9943 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9944 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9945 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9946 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9947 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9948 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9949 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9950 *shift = fglobal; 9951 PetscCall(VecDestroy(&flocal)); 9952 PetscCall(VecDestroy(&fglobalo)); 9953 PetscCall(VecDestroy(&clocal)); 9954 PetscCall(VecDestroy(&cglobalo)); 9955 PetscCall(VecDestroy(&rscale)); 9956 PetscCall(MatDestroy(&interpo)); 9957 PetscCall(DMDestroy(&dmfo)); 9958 PetscCall(DMDestroy(&dmco)); 9959 PetscFunctionReturn(PETSC_SUCCESS); 9960 } 9961 9962 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9963 { 9964 PetscObject shifto; 9965 Vec shift; 9966 9967 PetscFunctionBegin; 9968 if (!interp) { 9969 Vec rscale; 9970 9971 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9972 PetscCall(VecDestroy(&rscale)); 9973 } else { 9974 PetscCall(PetscObjectReference((PetscObject)interp)); 9975 } 9976 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9977 if (!shifto) { 9978 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9979 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9980 shifto = (PetscObject)shift; 9981 PetscCall(VecDestroy(&shift)); 9982 } 9983 shift = (Vec)shifto; 9984 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9985 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9986 PetscCall(MatDestroy(&interp)); 9987 PetscFunctionReturn(PETSC_SUCCESS); 9988 } 9989 9990 /* Pointwise interpolation 9991 Just code FEM for now 9992 u^f = I u^c 9993 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9994 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9995 I_{ij} = psi^f_i phi^c_j 9996 */ 9997 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9998 { 9999 PetscSection gsc, gsf; 10000 PetscInt m, n; 10001 void *ctx; 10002 DM cdm; 10003 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10004 10005 PetscFunctionBegin; 10006 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10007 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10008 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10009 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10010 10011 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10012 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10013 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10014 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10015 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10016 10017 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10018 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10019 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10020 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10021 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10022 if (scaling) { 10023 /* Use naive scaling */ 10024 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10025 } 10026 PetscFunctionReturn(PETSC_SUCCESS); 10027 } 10028 10029 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10030 { 10031 VecScatter ctx; 10032 10033 PetscFunctionBegin; 10034 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10035 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10036 PetscCall(VecScatterDestroy(&ctx)); 10037 PetscFunctionReturn(PETSC_SUCCESS); 10038 } 10039 10040 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[]) 10041 { 10042 const PetscInt Nc = uOff[1] - uOff[0]; 10043 PetscInt c; 10044 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10045 } 10046 10047 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 10048 { 10049 DM dmc; 10050 PetscDS ds; 10051 Vec ones, locmass; 10052 IS cellIS; 10053 PetscFormKey key; 10054 PetscInt depth; 10055 10056 PetscFunctionBegin; 10057 PetscCall(DMClone(dm, &dmc)); 10058 PetscCall(DMCopyDisc(dm, dmc)); 10059 PetscCall(DMGetDS(dmc, &ds)); 10060 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10061 PetscCall(DMCreateGlobalVector(dmc, mass)); 10062 PetscCall(DMGetLocalVector(dmc, &ones)); 10063 PetscCall(DMGetLocalVector(dmc, &locmass)); 10064 PetscCall(DMPlexGetDepth(dmc, &depth)); 10065 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10066 PetscCall(VecSet(locmass, 0.0)); 10067 PetscCall(VecSet(ones, 1.0)); 10068 key.label = NULL; 10069 key.value = 0; 10070 key.field = 0; 10071 key.part = 0; 10072 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10073 PetscCall(ISDestroy(&cellIS)); 10074 PetscCall(VecSet(*mass, 0.0)); 10075 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10076 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10077 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10078 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10079 PetscCall(DMDestroy(&dmc)); 10080 PetscFunctionReturn(PETSC_SUCCESS); 10081 } 10082 10083 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10084 { 10085 PetscSection gsc, gsf; 10086 PetscInt m, n; 10087 void *ctx; 10088 DM cdm; 10089 PetscBool regular; 10090 10091 PetscFunctionBegin; 10092 if (dmFine == dmCoarse) { 10093 DM dmc; 10094 PetscDS ds; 10095 PetscWeakForm wf; 10096 Vec u; 10097 IS cellIS; 10098 PetscFormKey key; 10099 PetscInt depth; 10100 10101 PetscCall(DMClone(dmFine, &dmc)); 10102 PetscCall(DMCopyDisc(dmFine, dmc)); 10103 PetscCall(DMGetDS(dmc, &ds)); 10104 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10105 PetscCall(PetscWeakFormClear(wf)); 10106 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10107 PetscCall(DMCreateMatrix(dmc, mass)); 10108 PetscCall(DMGetLocalVector(dmc, &u)); 10109 PetscCall(DMPlexGetDepth(dmc, &depth)); 10110 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10111 PetscCall(MatZeroEntries(*mass)); 10112 key.label = NULL; 10113 key.value = 0; 10114 key.field = 0; 10115 key.part = 0; 10116 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10117 PetscCall(ISDestroy(&cellIS)); 10118 PetscCall(DMRestoreLocalVector(dmc, &u)); 10119 PetscCall(DMDestroy(&dmc)); 10120 } else { 10121 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10122 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10123 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10124 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10125 10126 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10127 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10128 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10129 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10130 10131 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10132 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10133 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10134 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10135 } 10136 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10137 PetscFunctionReturn(PETSC_SUCCESS); 10138 } 10139 10140 /*@ 10141 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10142 10143 Input Parameter: 10144 . dm - The `DMPLEX` object 10145 10146 Output Parameter: 10147 . regular - The flag 10148 10149 Level: intermediate 10150 10151 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10152 @*/ 10153 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10154 { 10155 PetscFunctionBegin; 10156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10157 PetscAssertPointer(regular, 2); 10158 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10159 PetscFunctionReturn(PETSC_SUCCESS); 10160 } 10161 10162 /*@ 10163 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10164 10165 Input Parameters: 10166 + dm - The `DMPLEX` object 10167 - regular - The flag 10168 10169 Level: intermediate 10170 10171 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10172 @*/ 10173 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10174 { 10175 PetscFunctionBegin; 10176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10177 ((DM_Plex *)dm->data)->regularRefinement = regular; 10178 PetscFunctionReturn(PETSC_SUCCESS); 10179 } 10180 10181 /*@ 10182 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10183 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10184 10185 Not Collective 10186 10187 Input Parameter: 10188 . dm - The `DMPLEX` object 10189 10190 Output Parameters: 10191 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10192 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10193 10194 Level: intermediate 10195 10196 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10197 @*/ 10198 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10199 { 10200 DM_Plex *plex = (DM_Plex *)dm->data; 10201 10202 PetscFunctionBegin; 10203 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10204 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10205 if (anchorSection) *anchorSection = plex->anchorSection; 10206 if (anchorIS) *anchorIS = plex->anchorIS; 10207 PetscFunctionReturn(PETSC_SUCCESS); 10208 } 10209 10210 /*@ 10211 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10212 10213 Collective 10214 10215 Input Parameters: 10216 + dm - The `DMPLEX` object 10217 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10218 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10219 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10220 10221 Level: intermediate 10222 10223 Notes: 10224 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10225 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10226 combination of other points' degrees of freedom. 10227 10228 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10229 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10230 10231 The reference counts of `anchorSection` and `anchorIS` are incremented. 10232 10233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10234 @*/ 10235 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10236 { 10237 DM_Plex *plex = (DM_Plex *)dm->data; 10238 PetscMPIInt result; 10239 10240 PetscFunctionBegin; 10241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10242 if (anchorSection) { 10243 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10244 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10245 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10246 } 10247 if (anchorIS) { 10248 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10249 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10250 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10251 } 10252 10253 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10254 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10255 plex->anchorSection = anchorSection; 10256 10257 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10258 PetscCall(ISDestroy(&plex->anchorIS)); 10259 plex->anchorIS = anchorIS; 10260 10261 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10262 PetscInt size, a, pStart, pEnd; 10263 const PetscInt *anchors; 10264 10265 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10266 PetscCall(ISGetLocalSize(anchorIS, &size)); 10267 PetscCall(ISGetIndices(anchorIS, &anchors)); 10268 for (a = 0; a < size; a++) { 10269 PetscInt p; 10270 10271 p = anchors[a]; 10272 if (p >= pStart && p < pEnd) { 10273 PetscInt dof; 10274 10275 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10276 if (dof) { 10277 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10278 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10279 } 10280 } 10281 } 10282 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10283 } 10284 /* reset the generic constraints */ 10285 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10286 PetscFunctionReturn(PETSC_SUCCESS); 10287 } 10288 10289 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10290 { 10291 PetscSection anchorSection; 10292 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10293 10294 PetscFunctionBegin; 10295 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10296 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10297 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10298 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10299 if (numFields) { 10300 PetscInt f; 10301 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10302 10303 for (f = 0; f < numFields; f++) { 10304 PetscInt numComp; 10305 10306 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10307 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10308 } 10309 } 10310 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10311 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10312 pStart = PetscMax(pStart, sStart); 10313 pEnd = PetscMin(pEnd, sEnd); 10314 pEnd = PetscMax(pStart, pEnd); 10315 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10316 for (p = pStart; p < pEnd; p++) { 10317 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10318 if (dof) { 10319 PetscCall(PetscSectionGetDof(section, p, &dof)); 10320 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10321 for (f = 0; f < numFields; f++) { 10322 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10323 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10324 } 10325 } 10326 } 10327 PetscCall(PetscSectionSetUp(*cSec)); 10328 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10329 PetscFunctionReturn(PETSC_SUCCESS); 10330 } 10331 10332 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10333 { 10334 PetscSection aSec; 10335 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10336 const PetscInt *anchors; 10337 PetscInt numFields, f; 10338 IS aIS; 10339 MatType mtype; 10340 PetscBool iscuda, iskokkos; 10341 10342 PetscFunctionBegin; 10343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10344 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10345 PetscCall(PetscSectionGetStorageSize(section, &n)); 10346 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10347 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10348 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10349 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10350 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10351 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10352 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10353 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10354 else mtype = MATSEQAIJ; 10355 PetscCall(MatSetType(*cMat, mtype)); 10356 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10357 PetscCall(ISGetIndices(aIS, &anchors)); 10358 /* cSec will be a subset of aSec and section */ 10359 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10360 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10361 PetscCall(PetscMalloc1(m + 1, &i)); 10362 i[0] = 0; 10363 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10364 for (p = pStart; p < pEnd; p++) { 10365 PetscInt rDof, rOff, r; 10366 10367 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10368 if (!rDof) continue; 10369 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10370 if (numFields) { 10371 for (f = 0; f < numFields; f++) { 10372 annz = 0; 10373 for (r = 0; r < rDof; r++) { 10374 a = anchors[rOff + r]; 10375 if (a < sStart || a >= sEnd) continue; 10376 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10377 annz += aDof; 10378 } 10379 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10380 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10381 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10382 } 10383 } else { 10384 annz = 0; 10385 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10386 for (q = 0; q < dof; q++) { 10387 a = anchors[rOff + q]; 10388 if (a < sStart || a >= sEnd) continue; 10389 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10390 annz += aDof; 10391 } 10392 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10393 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10394 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10395 } 10396 } 10397 nnz = i[m]; 10398 PetscCall(PetscMalloc1(nnz, &j)); 10399 offset = 0; 10400 for (p = pStart; p < pEnd; p++) { 10401 if (numFields) { 10402 for (f = 0; f < numFields; f++) { 10403 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10404 for (q = 0; q < dof; q++) { 10405 PetscInt rDof, rOff, r; 10406 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10407 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10408 for (r = 0; r < rDof; r++) { 10409 PetscInt s; 10410 10411 a = anchors[rOff + r]; 10412 if (a < sStart || a >= sEnd) continue; 10413 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10414 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10415 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10416 } 10417 } 10418 } 10419 } else { 10420 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10421 for (q = 0; q < dof; q++) { 10422 PetscInt rDof, rOff, r; 10423 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10424 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10425 for (r = 0; r < rDof; r++) { 10426 PetscInt s; 10427 10428 a = anchors[rOff + r]; 10429 if (a < sStart || a >= sEnd) continue; 10430 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10431 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10432 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10433 } 10434 } 10435 } 10436 } 10437 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10438 PetscCall(PetscFree(i)); 10439 PetscCall(PetscFree(j)); 10440 PetscCall(ISRestoreIndices(aIS, &anchors)); 10441 PetscFunctionReturn(PETSC_SUCCESS); 10442 } 10443 10444 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10445 { 10446 DM_Plex *plex = (DM_Plex *)dm->data; 10447 PetscSection anchorSection, section, cSec; 10448 Mat cMat; 10449 10450 PetscFunctionBegin; 10451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10452 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10453 if (anchorSection) { 10454 PetscInt Nf; 10455 10456 PetscCall(DMGetLocalSection(dm, §ion)); 10457 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10458 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10459 PetscCall(DMGetNumFields(dm, &Nf)); 10460 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10461 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10462 PetscCall(PetscSectionDestroy(&cSec)); 10463 PetscCall(MatDestroy(&cMat)); 10464 } 10465 PetscFunctionReturn(PETSC_SUCCESS); 10466 } 10467 10468 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10469 { 10470 IS subis; 10471 PetscSection section, subsection; 10472 10473 PetscFunctionBegin; 10474 PetscCall(DMGetLocalSection(dm, §ion)); 10475 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10476 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10477 /* Create subdomain */ 10478 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10479 /* Create submodel */ 10480 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10481 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10482 PetscCall(DMSetLocalSection(*subdm, subsection)); 10483 PetscCall(PetscSectionDestroy(&subsection)); 10484 PetscCall(DMCopyDisc(dm, *subdm)); 10485 /* Create map from submodel to global model */ 10486 if (is) { 10487 PetscSection sectionGlobal, subsectionGlobal; 10488 IS spIS; 10489 const PetscInt *spmap; 10490 PetscInt *subIndices; 10491 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10492 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10493 10494 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10495 PetscCall(ISGetIndices(spIS, &spmap)); 10496 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10497 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10498 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10499 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10500 for (p = pStart; p < pEnd; ++p) { 10501 PetscInt gdof, pSubSize = 0; 10502 10503 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10504 if (gdof > 0) { 10505 for (f = 0; f < Nf; ++f) { 10506 PetscInt fdof, fcdof; 10507 10508 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10509 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10510 pSubSize += fdof - fcdof; 10511 } 10512 subSize += pSubSize; 10513 if (pSubSize) { 10514 if (bs < 0) { 10515 bs = pSubSize; 10516 } else if (bs != pSubSize) { 10517 /* Layout does not admit a pointwise block size */ 10518 bs = 1; 10519 } 10520 } 10521 } 10522 } 10523 /* Must have same blocksize on all procs (some might have no points) */ 10524 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10525 bsLocal[1] = bs; 10526 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10527 if (bsMinMax[0] != bsMinMax[1]) { 10528 bs = 1; 10529 } else { 10530 bs = bsMinMax[0]; 10531 } 10532 PetscCall(PetscMalloc1(subSize, &subIndices)); 10533 for (p = pStart; p < pEnd; ++p) { 10534 PetscInt gdof, goff; 10535 10536 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10537 if (gdof > 0) { 10538 const PetscInt point = spmap[p]; 10539 10540 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10541 for (f = 0; f < Nf; ++f) { 10542 PetscInt fdof, fcdof, fc, f2, poff = 0; 10543 10544 /* Can get rid of this loop by storing field information in the global section */ 10545 for (f2 = 0; f2 < f; ++f2) { 10546 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10547 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10548 poff += fdof - fcdof; 10549 } 10550 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10551 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10552 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10553 } 10554 } 10555 } 10556 PetscCall(ISRestoreIndices(spIS, &spmap)); 10557 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10558 if (bs > 1) { 10559 /* We need to check that the block size does not come from non-contiguous fields */ 10560 PetscInt i, j, set = 1; 10561 for (i = 0; i < subSize; i += bs) { 10562 for (j = 0; j < bs; ++j) { 10563 if (subIndices[i + j] != subIndices[i] + j) { 10564 set = 0; 10565 break; 10566 } 10567 } 10568 } 10569 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10570 } 10571 /* Attach nullspace */ 10572 for (f = 0; f < Nf; ++f) { 10573 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10574 if ((*subdm)->nullspaceConstructors[f]) break; 10575 } 10576 if (f < Nf) { 10577 MatNullSpace nullSpace; 10578 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10579 10580 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10581 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10582 } 10583 } 10584 PetscFunctionReturn(PETSC_SUCCESS); 10585 } 10586 10587 /*@ 10588 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10589 10590 Input Parameters: 10591 + dm - The `DM` 10592 - dummy - unused argument 10593 10594 Options Database Key: 10595 . -dm_plex_monitor_throughput - Activate the monitor 10596 10597 Level: developer 10598 10599 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10600 @*/ 10601 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10602 { 10603 PetscLogHandler default_handler; 10604 10605 PetscFunctionBegin; 10606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10607 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10608 if (default_handler) { 10609 PetscLogEvent event; 10610 PetscEventPerfInfo eventInfo; 10611 PetscReal cellRate, flopRate; 10612 PetscInt cStart, cEnd, Nf, N; 10613 const char *name; 10614 10615 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10616 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10617 PetscCall(DMGetNumFields(dm, &Nf)); 10618 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10619 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10620 N = (cEnd - cStart) * Nf * eventInfo.count; 10621 flopRate = eventInfo.flops / eventInfo.time; 10622 cellRate = N / eventInfo.time; 10623 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))); 10624 } else { 10625 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."); 10626 } 10627 PetscFunctionReturn(PETSC_SUCCESS); 10628 } 10629